require 'rails_helper' require 'time' describe Agents::ImapFolderAgent do describe 'checking IMAP' do before do @site = { 'expected_update_period_in_days' => 1, 'host' => 'mail.example.net', 'ssl' => true, 'username' => 'foo', 'password' => 'bar', 'folders' => ['INBOX'], 'conditions' => { } } @checker = Agents::ImapFolderAgent.new(:name => 'Example', :options => @site, :keep_events_for => 2.days) @checker.user = users(:bob) @checker.save! message_mixin = Module.new { def folder 'INBOX' end def uidvalidity 100 end def has_attachment? false end def body_parts(mime_types = %[text/plain text/enriched text/html]) mime_types.map { |type| all_parts.find { |part| part.mime_type == type } }.compact.map! { |part| part.extend(Agents::ImapFolderAgent::Message::Scrubbed) } end include Agents::ImapFolderAgent::Message::Scrubbed } @mails = [ Mail.read(Rails.root.join('spec/data_fixtures/imap1.eml')).tap { |mail| mail.extend(message_mixin) stub(mail).uid.returns(1) }, Mail.read(Rails.root.join('spec/data_fixtures/imap2.eml')).tap { |mail| mail.extend(message_mixin) stub(mail).uid.returns(2) stub(mail).has_attachment?.returns(true) }, ] stub(@checker).each_unread_mail.returns { |yielder| seen = @checker.lastseen notified = @checker.notified @mails.each_with_object(notified) { |mail| yielder[mail, notified] seen[mail.uidvalidity] = mail.uid } @checker.lastseen = seen @checker.notified = notified nil } @payloads = [ { 'folder' => 'INBOX', 'from' => 'nanashi.gombeh@example.jp', 'to' => ['jane.doe@example.com', 'john.doe@example.com'], 'cc' => [], 'date' => '2014-05-09T16:00:00+09:00', 'subject' => 'some subject', 'body' => "Some plain text\nSome second line\n", 'has_attachment' => false, 'matches' => {}, 'mime_type' => 'text/plain', }, { 'folder' => 'INBOX', 'from' => 'john.doe@example.com', 'to' => ['jane.doe@example.com', 'nanashi.gombeh@example.jp'], 'cc' => [], 'subject' => 'Re: some subject', 'body' => "Some reply\n", 'date' => '2014-05-09T17:00:00+09:00', 'has_attachment' => true, 'matches' => {}, 'mime_type' => 'text/plain', } ] end describe 'validations' do before do expect(@checker).to be_valid end it 'should validate the integer fields' do @checker.options['expected_update_period_in_days'] = 'nonsense' expect(@checker).not_to be_valid @checker.options['expected_update_period_in_days'] = '2' expect(@checker).to be_valid @checker.options['port'] = -1 expect(@checker).not_to be_valid @checker.options['port'] = 'imap' expect(@checker).not_to be_valid @checker.options['port'] = '143' expect(@checker).to be_valid @checker.options['port'] = 993 expect(@checker).to be_valid end it 'should validate the boolean fields' do %w[ssl mark_as_read].each do |key| @checker.options[key] = 1 expect(@checker).not_to be_valid @checker.options[key] = false expect(@checker).to be_valid @checker.options[key] = 'true' expect(@checker).to be_valid @checker.options[key] = '' expect(@checker).to be_valid end end it 'should validate regexp conditions' do @checker.options['conditions'] = { 'subject' => '(foo' } expect(@checker).not_to be_valid @checker.options['conditions'] = { 'body' => '***' } expect(@checker).not_to be_valid @checker.options['conditions'] = { 'subject' => '\ARe:', 'body' => '(?http://\S+)' } expect(@checker).to be_valid end end describe '#check' do it 'should check for mails and save memory' do expect { @checker.check }.to change { Event.count }.by(2) expect(@checker.notified.sort).to eq(@mails.map(&:message_id).sort) expect(@checker.lastseen).to eq(@mails.each_with_object(@checker.make_seen) { |mail, seen| seen[mail.uidvalidity] = mail.uid }) Event.last(2).map(&:payload) == @payloads expect { @checker.check }.not_to change { Event.count } end it 'should narrow mails by To' do @checker.options['conditions']['to'] = 'John.Doe@*' expect { @checker.check }.to change { Event.count }.by(1) expect(@checker.notified.sort).to eq([@mails.first.message_id]) expect(@checker.lastseen).to eq(@mails.each_with_object(@checker.make_seen) { |mail, seen| seen[mail.uidvalidity] = mail.uid }) expect(Event.last.payload).to eq(@payloads.first) expect { @checker.check }.not_to change { Event.count } end it 'should perform regexp matching and save named captures' do @checker.options['conditions'].update( 'subject' => '\ARe: (?.+)', 'body' => 'Some (?.+) reply', ) expect { @checker.check }.to change { Event.count }.by(1) expect(@checker.notified.sort).to eq([@mails.last.message_id]) expect(@checker.lastseen).to eq(@mails.each_with_object(@checker.make_seen) { |mail, seen| seen[mail.uidvalidity] = mail.uid }) expect(Event.last.payload).to eq(@payloads.last.update( 'body' => "
Some HTML reply
\n", 'matches' => { 'a' => 'some subject', 'b' => 'HTML' }, 'mime_type' => 'text/html', )) expect { @checker.check }.not_to change { Event.count } end it 'should narrow mails by has_attachment (true)' do @checker.options['conditions']['has_attachment'] = true expect { @checker.check }.to change { Event.count }.by(1) expect(Event.last.payload['subject']).to eq('Re: some subject') end it 'should narrow mails by has_attachment (false)' do @checker.options['conditions']['has_attachment'] = false expect { @checker.check }.to change { Event.count }.by(1) expect(Event.last.payload['subject']).to eq('some subject') end it 'should narrow mail parts by MIME types' do @checker.options['mime_types'] = %w[text/plain] @checker.options['conditions'].update( 'subject' => '\ARe: (?
.+)', 'body' => 'Some (?.+) reply', ) expect { @checker.check }.not_to change { Event.count } expect(@checker.notified.sort).to eq([]) expect(@checker.lastseen).to eq(@mails.each_with_object(@checker.make_seen) { |mail, seen| seen[mail.uidvalidity] = mail.uid }) end it 'should never mark mails as read unless mark_as_read is true' do @mails.each { |mail| stub(mail).mark_as_read.never } expect { @checker.check }.to change { Event.count }.by(2) end it 'should mark mails as read if mark_as_read is true' do @checker.options['mark_as_read'] = true @mails.each { |mail| stub(mail).mark_as_read.once } expect { @checker.check }.to change { Event.count }.by(2) end it 'should create just one event for multiple mails with the same Message-Id' do @mails.first.message_id = @mails.last.message_id @checker.options['mark_as_read'] = true @mails.each { |mail| stub(mail).mark_as_read.once } expect { @checker.check }.to change { Event.count }.by(1) end end end describe 'Agents::ImapFolderAgent::Message::Scrubbed' do before do @class = Class.new do def subject "broken\xB7subject\xB6" end def body "broken\xB7body\xB6" end include Agents::ImapFolderAgent::Message::Scrubbed end @object = @class.new end describe '#scrubbed' do it 'should return a scrubbed string' do expect(@object.scrubbed(:subject)).to eq("brokensubject") expect(@object.scrubbed(:body)).to eq("brokenbody") end end end end