# Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
require 'rails_helper'
RSpec.describe Channel::EmailParser, type: :model do
describe '#parse' do
shared_examples 'parses email correctly' do |stored_email|
context "for #{stored_email}" do
let(:yml_file) { stored_email.ext('yml') }
let(:content) { YAML.load_file(yml_file, permitted_classes: [ActiveSupport::HashWithIndifferentAccess]) }
let(:parsed) { described_class.new.parse(File.read(stored_email)) }
let(:expected_msg) { content.except(:attachments) }
let(:parsed_msg) { parsed.slice(*expected_msg.keys) }
let(:content_attachments_md5s) { (content[:attachments]&.map { |a| Digest::MD5.hexdigest(a[:data]) } || []).to_set }
let(:parsed_attachments_md5s) { (parsed[:attachments]&.map { |a| Digest::MD5.hexdigest(a[:data]) } || []).to_set }
it 'parses correctly' do
expect(File).to exist(yml_file)
expect(parsed_msg).to include(expected_msg)
expect(content_attachments_md5s).to be_subset(parsed_attachments_md5s)
end
end
end
describe 'when mail does not contain any sender specification' do
subject(:instance) { described_class.new }
let(:raw_mail) { <<~RAW.chomp }
To: baz@qux.net
Subject: Foo
Lorem ipsum dolor
RAW
it 'raises error even if exception is false' do
expect { described_class.new.parse(raw_mail) }
.to raise_error(Exceptions::MissingAttribute, 'Could not parse any sender attribute from the email. Checked fields: From, Reply-To, Return-Path, Sender')
end
end
describe 'when mail does not contain any sender specification with disabled missing attribute exceptions' do
subject(:instance) { described_class.new }
let(:raw_mail) { <<~RAW.chomp }
To: baz@qux.net
Subject: Foo
Lorem ipsum dolor
RAW
it 'prevents raising an error' do
expect { described_class.new.parse(raw_mail, allow_missing_attribute_exceptions: false) }
.not_to raise_error
end
end
# To write new .yml files for emails you can use the following code:
#
# File.write('test/data/mail/mailXXX.yml', Channel::EmailParser.new.parse(File.read('test/data/mail/mailXXX.box')).slice(:from, :from_email, :from_display_name, :to, :cc, :subject, :body, :content_type, :'reply-to', :attachments).to_yaml)
#
# To renew all existing files, you can use the following code:
#
# Dir.glob(Rails.root.join('test/data/mail/mail*.box')).each { |mail_file| File.write(mail_file.gsub('.box', '.yml'), Channel::EmailParser.new.parse(File.read(mail_file)).slice(:from, :from_email, :from_display_name, :to, :cc, :subject, :body, :content_type, :'reply-to', :attachments).to_yaml) }
#
context 'when checking a bunch of stored emails for correct parsing behaviour' do
tests = Dir.glob(Rails.root.join('test/data/mail/mail*.box')).each do |stored_email| # rubocop:disable Rails/RootPathnameMethods
include_examples('parses email correctly', stored_email)
end
it 'ensures tests were dynamically generated' do
expect(tests.count).to eq(108)
end
end
# regression test for issue 2390 - Add a postmaster filter to not show emails with potential issue
describe 'handling HTML links in message content' do
context 'with under 5,000 links' do
it 'parses message content as normal' do
expect(described_class.new.parse(<<~RAW)[:body]).to start_with('
#{Array.new(10) { 'Dummy Link' }.join(' ')}