imap_folder_agent_spec.rb 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. require 'spec_helper'
  2. require 'time'
  3. describe Agents::ImapFolderAgent do
  4. describe 'checking IMAP' do
  5. before do
  6. @site = {
  7. 'expected_update_period_in_days' => 1,
  8. 'host' => 'mail.example.net',
  9. 'ssl' => true,
  10. 'username' => 'foo',
  11. 'password' => 'bar',
  12. 'folders' => ['INBOX'],
  13. 'conditions' => {
  14. }
  15. }
  16. @checker = Agents::ImapFolderAgent.new(:name => 'Example', :options => @site, :keep_events_for => 2)
  17. @checker.user = users(:bob)
  18. @checker.save!
  19. message_mixin = Module.new {
  20. def folder
  21. 'INBOX'
  22. end
  23. def uidvalidity
  24. 100
  25. end
  26. def has_attachment?
  27. false
  28. end
  29. def body_parts(mime_types = %[text/plain text/enriched text/html])
  30. mime_types.map { |type|
  31. all_parts.find { |part|
  32. part.mime_type == type
  33. }
  34. }.compact
  35. end
  36. }
  37. @mails = [
  38. Mail.read(Rails.root.join('spec/data_fixtures/imap1.eml')).tap { |mail|
  39. mail.extend(message_mixin)
  40. stub(mail).uid.returns(1)
  41. },
  42. Mail.read(Rails.root.join('spec/data_fixtures/imap2.eml')).tap { |mail|
  43. mail.extend(message_mixin)
  44. stub(mail).uid.returns(2)
  45. stub(mail).has_attachment?.returns(true)
  46. },
  47. ]
  48. stub(@checker).each_unread_mail.returns { |yielder|
  49. seen = @checker.lastseen
  50. notified = @checker.notified
  51. @mails.each_with_object(notified) { |mail|
  52. yielder[mail, notified]
  53. seen[mail.uidvalidity] = mail.uid
  54. }
  55. @checker.lastseen = seen
  56. @checker.notified = notified
  57. nil
  58. }
  59. @payloads = [
  60. {
  61. 'folder' => 'INBOX',
  62. 'from' => 'nanashi.gombeh@example.jp',
  63. 'to' => ['jane.doe@example.com', 'john.doe@example.com'],
  64. 'cc' => [],
  65. 'date' => '2014-05-09T16:00:00+09:00',
  66. 'subject' => 'some subject',
  67. 'body' => "Some plain text\nSome second line\n",
  68. 'has_attachment' => false,
  69. 'matches' => {},
  70. 'mime_type' => 'text/plain',
  71. },
  72. {
  73. 'folder' => 'INBOX',
  74. 'from' => 'john.doe@example.com',
  75. 'to' => ['jane.doe@example.com', 'nanashi.gombeh@example.jp'],
  76. 'cc' => [],
  77. 'subject' => 'Re: some subject',
  78. 'body' => "Some reply\n",
  79. 'date' => '2014-05-09T17:00:00+09:00',
  80. 'has_attachment' => true,
  81. 'matches' => {},
  82. 'mime_type' => 'text/plain',
  83. }
  84. ]
  85. end
  86. describe 'validations' do
  87. before do
  88. expect(@checker).to be_valid
  89. end
  90. it 'should validate the integer fields' do
  91. @checker.options['expected_update_period_in_days'] = 'nonsense'
  92. expect(@checker).not_to be_valid
  93. @checker.options['expected_update_period_in_days'] = '2'
  94. expect(@checker).to be_valid
  95. @checker.options['port'] = -1
  96. expect(@checker).not_to be_valid
  97. @checker.options['port'] = 'imap'
  98. expect(@checker).not_to be_valid
  99. @checker.options['port'] = '143'
  100. expect(@checker).to be_valid
  101. @checker.options['port'] = 993
  102. expect(@checker).to be_valid
  103. end
  104. it 'should validate the boolean fields' do
  105. %w[ssl mark_as_read].each do |key|
  106. @checker.options[key] = 1
  107. expect(@checker).not_to be_valid
  108. @checker.options[key] = false
  109. expect(@checker).to be_valid
  110. @checker.options[key] = 'true'
  111. expect(@checker).to be_valid
  112. @checker.options[key] = ''
  113. expect(@checker).to be_valid
  114. end
  115. end
  116. it 'should validate regexp conditions' do
  117. @checker.options['conditions'] = {
  118. 'subject' => '(foo'
  119. }
  120. expect(@checker).not_to be_valid
  121. @checker.options['conditions'] = {
  122. 'body' => '***'
  123. }
  124. expect(@checker).not_to be_valid
  125. @checker.options['conditions'] = {
  126. 'subject' => '\ARe:',
  127. 'body' => '(?<foo>http://\S+)'
  128. }
  129. expect(@checker).to be_valid
  130. end
  131. end
  132. describe '#check' do
  133. it 'should check for mails and save memory' do
  134. expect { @checker.check }.to change { Event.count }.by(2)
  135. expect(@checker.notified.sort).to eq(@mails.map(&:message_id).sort)
  136. expect(@checker.lastseen).to eq(@mails.each_with_object(@checker.make_seen) { |mail, seen|
  137. seen[mail.uidvalidity] = mail.uid
  138. })
  139. Event.last(2).map(&:payload) == @payloads
  140. expect { @checker.check }.not_to change { Event.count }
  141. end
  142. it 'should narrow mails by To' do
  143. @checker.options['conditions']['to'] = 'John.Doe@*'
  144. expect { @checker.check }.to change { Event.count }.by(1)
  145. expect(@checker.notified.sort).to eq([@mails.first.message_id])
  146. expect(@checker.lastseen).to eq(@mails.each_with_object(@checker.make_seen) { |mail, seen|
  147. seen[mail.uidvalidity] = mail.uid
  148. })
  149. expect(Event.last.payload).to eq(@payloads.first)
  150. expect { @checker.check }.not_to change { Event.count }
  151. end
  152. it 'should perform regexp matching and save named captures' do
  153. @checker.options['conditions'].update(
  154. 'subject' => '\ARe: (?<a>.+)',
  155. 'body' => 'Some (?<b>.+) reply',
  156. )
  157. expect { @checker.check }.to change { Event.count }.by(1)
  158. expect(@checker.notified.sort).to eq([@mails.last.message_id])
  159. expect(@checker.lastseen).to eq(@mails.each_with_object(@checker.make_seen) { |mail, seen|
  160. seen[mail.uidvalidity] = mail.uid
  161. })
  162. expect(Event.last.payload).to eq(@payloads.last.update(
  163. 'body' => "<div dir=\"ltr\">Some HTML reply<br></div>\n",
  164. 'matches' => { 'a' => 'some subject', 'b' => 'HTML' },
  165. 'mime_type' => 'text/html',
  166. ))
  167. expect { @checker.check }.not_to change { Event.count }
  168. end
  169. it 'should narrow mails by has_attachment (true)' do
  170. @checker.options['conditions']['has_attachment'] = true
  171. expect { @checker.check }.to change { Event.count }.by(1)
  172. expect(Event.last.payload['subject']).to eq('Re: some subject')
  173. end
  174. it 'should narrow mails by has_attachment (false)' do
  175. @checker.options['conditions']['has_attachment'] = false
  176. expect { @checker.check }.to change { Event.count }.by(1)
  177. expect(Event.last.payload['subject']).to eq('some subject')
  178. end
  179. it 'should narrow mail parts by MIME types' do
  180. @checker.options['mime_types'] = %w[text/plain]
  181. @checker.options['conditions'].update(
  182. 'subject' => '\ARe: (?<a>.+)',
  183. 'body' => 'Some (?<b>.+) reply',
  184. )
  185. expect { @checker.check }.not_to change { Event.count }
  186. expect(@checker.notified.sort).to eq([])
  187. expect(@checker.lastseen).to eq(@mails.each_with_object(@checker.make_seen) { |mail, seen|
  188. seen[mail.uidvalidity] = mail.uid
  189. })
  190. end
  191. it 'should never mark mails as read unless mark_as_read is true' do
  192. @mails.each { |mail|
  193. stub(mail).mark_as_read.never
  194. }
  195. expect { @checker.check }.to change { Event.count }.by(2)
  196. end
  197. it 'should mark mails as read if mark_as_read is true' do
  198. @checker.options['mark_as_read'] = true
  199. @mails.each { |mail|
  200. stub(mail).mark_as_read.once
  201. }
  202. expect { @checker.check }.to change { Event.count }.by(2)
  203. end
  204. it 'should create just one event for multiple mails with the same Message-Id' do
  205. @mails.first.message_id = @mails.last.message_id
  206. @checker.options['mark_as_read'] = true
  207. @mails.each { |mail|
  208. stub(mail).mark_as_read.once
  209. }
  210. expect { @checker.check }.to change { Event.count }.by(1)
  211. end
  212. end
  213. end
  214. end