123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
- require 'rails_helper'
- RSpec.describe FailedEmail, :aggregate_failures, type: :model do
- subject(:instance) { create(:failed_email) }
- describe '#parsing_error' do
- it 'sets parsing error' do
- instance.parsing_error = 'text'
- expect(instance).to have_attributes(parsing_error: 'text')
- end
- it 'sets parsing error off error' do
- instance.parsing_error = StandardError.new('Sample error')
- expect(instance).to have_attributes(parsing_error: include('Sample error'))
- end
- end
- describe '.by_filepath' do
- let!(:failed_email) { create(:failed_email) }
- it 'finds the email by filename' do
- expect(described_class.by_filepath("some/folder/#{failed_email.id}.eml")).to eq(failed_email)
- end
- it 'finds the email by id' do
- expect(described_class.by_filepath(failed_email.id.to_s)).to eq(failed_email)
- end
- it 'does not find with another extension' do
- expect(described_class.by_filepath("some/folder/#{failed_email.id}.yml")).to be_nil
- end
- it 'does not find if not existant' do
- expect(described_class.by_filepath('1337.eml')).to be_nil
- end
- end
- describe '#reprocess' do
- context 'when it succeeds' do
- it 'destroys entry' do
- instance.reprocess
- expect(instance).to be_destroyed
- end
- it 'creates a ticket' do
- ticket = instance.reprocess
- expect(ticket.articles.first).to have_attributes(
- body: 'Some Text'
- )
- end
- end
- context 'when it succeeds and an ignore postmaster filter exists' do
- let!(:failed_email) { create(:failed_email, :invalid) }
- # init postmaster filter
- before do
- failed_email.data = "From: ME Bob <me@example.com>\nTo: customer@example.com\nSubject: some subject\n\nSome Text"
- failed_email.save!
- create(:postmaster_filter,
- match: {
- 'subject' => {
- 'operator' => 'contains',
- 'value' => 'subject',
- },
- },
- perform: {
- 'x-zammad-ignore' => { 'value' => 'true' },
- },)
- end
- it 'destroys entry' do
- failed_email.reprocess
- expect(failed_email).to be_destroyed
- end
- it 'does not create a ticket' do
- expect { failed_email.reprocess }.not_to change(Ticket, :count)
- end
- it 'successfully processed by postmaster filter' do
- expect(failed_email.reprocess).to eq({})
- end
- end
- context 'when it fails' do
- before do
- allow_any_instance_of(Channel::EmailParser)
- .to receive(:process_with_timeout)
- .and_return([])
- end
- it 'increases retries count on failure' do
- expect { instance.reprocess }
- .to change(instance, :retries).by(1)
- end
- it 'does not create a ticket' do
- expect { instance.reprocess }.not_to change(Ticket, :count)
- end
- end
- end
- describe '.reprocess_all' do
- let!(:failed_email) { create(:failed_email, :invalid) }
- let!(:failed_but_correct_email) { create(:failed_email) }
- before do
- failed_email
- failed_but_correct_email
- end
- it 'creates one ticket for the parseable mail and keeps the other' do
- expect { described_class.reprocess_all }
- .to change(Ticket, :count).by(1)
- .and(change(described_class, :count).by(-1))
- end
- it 'returns a list of processed email files' do
- expect(described_class.reprocess_all).to eq(["#{failed_but_correct_email.id}.eml"])
- end
- end
- describe '.export_all' do
- it 'calls export with all records' do
- instance
- allow_any_instance_of(described_class)
- .to receive(:export)
- .with('path')
- .and_return('path/file.eml')
- expect(described_class.export_all('path'))
- .to contain_exactly('path/file.eml')
- end
- end
- describe '#export' do
- it 'creates a file' do
- path = instance.export
- expect(File.binread(path)).to eq(instance.data)
- end
- end
- describe '.import_all' do
- it 'calls import with all files' do
- path = described_class.generate_path
- instance.export(path)
- allow(described_class)
- .to receive(:import)
- .with(path.join("#{instance.id}.eml"))
- .and_return('imported_path')
- expect(described_class.import_all(path))
- .to contain_exactly('imported_path')
- end
- end
- describe '.import' do
- let(:path) { described_class.generate_path }
- let!(:file_path) { instance.export(path) }
- let(:sample_text) { "#{instance.data}\n" }
- let(:import_result) { described_class.import(path.join("#{instance.id}.eml")) }
- after do
- file_path.unlink if file_path.exist?
- end
- context 'with unprocessable content' do
- subject(:instance) { create(:failed_email, data: Faker::Lorem.sentence) }
- it 'fails on reimporting' do
- expect(import_result).to be_nil
- expect(instance.reload.retries).to eq(2)
- end
- it 'keeps the file' do
- expect(file_path).to exist
- end
- context 'with changed valid file content' do
- before { File.binwrite(file_path, create(:failed_email).data) }
- it 'reimports correctly' do
- expect { import_result }.to change(Ticket, :count).by(1)
- expect(import_result).to eq(file_path)
- expect(file_path).not_to exist
- end
- end
- context 'with changed invalid file content' do
- before { File.binwrite(file_path, Faker::Lorem.sentence) }
- it 'fails to import again' do
- expect(import_result).to be_nil
- expect(instance.reload.retries).to eq(2)
- end
- end
- end
- it 'returns nil if database row does not exist' do
- expect(described_class.import(Pathname.new('tmp/1337.eml'))).to be_nil
- end
- end
- end
|