Skip to content

Commit

Permalink
Implement null mx record, multihomed mx supporting
Browse files Browse the repository at this point in the history
  • Loading branch information
bestwebua committed Apr 8, 2019
1 parent 766a939 commit 5a819a8
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 23 deletions.
26 changes: 19 additions & 7 deletions lib/truemail/validate/mx.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ class Mx < Truemail::Validate::Base
require 'resolv'

ERROR = 'target host(s) not found'
NULL_MX_RECORD = 'null_mx_record'

def run
return false unless Truemail::Validate::Regex.check(result)
result.domain = result.email[Truemail::RegexConstant::REGEX_DOMAIN_FROM_EMAIL, 1]
return true if success(mx_lookup)
add_error(Truemail::Validate::Mx::ERROR)
return true if success(mx_lookup && domain_not_include_null_mx)
mail_servers.clear && add_error(Truemail::Validate::Mx::ERROR)
false
end

Expand All @@ -28,17 +29,28 @@ def mx_lookup
end

def fetch_target_hosts(hosts)
result.mail_servers.push(*hosts)
mail_servers.push(*hosts)
end

def null_mx?(domain_mx_records)
mx_record = domain_mx_records.first
domain_mx_records.one? && mx_record.preference.zero? && mx_record.exchange.to_s.empty?
end

def domain_not_include_null_mx
!mail_servers.include?(Truemail::Validate::Mx::NULL_MX_RECORD)
end

def mx_records(domain)
Resolv::DNS.new.getresources(domain, Resolv::DNS::Resource::IN::MX).sort_by(&:preference).map do |mx_record|
Resolv.getaddress(mx_record.exchange.to_s)
end
domain_mx_records = Resolv::DNS.new.getresources(domain, Resolv::DNS::Resource::IN::MX)
return [Truemail::Validate::Mx::NULL_MX_RECORD] if null_mx?(domain_mx_records)
domain_mx_records.sort_by(&:preference).map do |mx_record|
Resolv.getaddresses(mx_record.exchange.to_s)
end.flatten
end

def mail_servers_found?
!result.mail_servers.empty?
!mail_servers.empty?
end

def hosts_from_mx_records?
Expand Down
65 changes: 49 additions & 16 deletions spec/truemail/validate/mx_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

describe 'defined constants' do
specify { expect(described_class).to be_const_defined(:ERROR) }
specify { expect(described_class).to be_const_defined(:NULL_MX_RECORD) }
end

describe '.check' do
Expand Down Expand Up @@ -42,26 +43,58 @@
context 'when mx records found' do
let(:mx_records_file) { "#{File.expand_path('../../', __dir__)}/support/objects/mx_records.yml" }

before do
allow(Resolv::DNS).to receive_message_chain(:new, :getresources).and_return(mx_records_object)
allow(Resolv).to receive(:getaddress).and_return(host_address)
end
before { allow(Resolv::DNS).to receive_message_chain(:new, :getresources).and_return(mx_records_object) }

specify do
expect(mx_validator_instance).to receive(:hosts_from_mx_records?).and_call_original
expect(mx_validator_instance).not_to receive(:hosts_from_cname_records?)
expect(mx_validator_instance).not_to receive(:host_from_a_record?)
context 'with null mx' do
let(:target_mx_record) { mx_records_object.first }

expect { mx_validator }
.to change(result_instance, :domain)
.from(nil).to(email[Truemail::RegexConstant::REGEX_EMAIL_PATTERN, 3])
.and change(result_instance, :mail_servers)
.from([]).to(mail_servers_by_ip)
.and not_change(result_instance, :success)
before do
allow(mx_validator_instance).to receive(:hosts_from_mx_records?).and_call_original
allow(mx_validator_instance).to receive(:mx_records).and_call_original
allow(mx_validator_instance).to receive(:null_mx?).and_call_original

allow(mx_records_object).to receive(:one?).and_return(true)
allow(target_mx_record).to receive_message_chain(:preference, :zero?).and_return(true)
allow(target_mx_record).to receive_message_chain(:exchange, :to_s, :empty?).and_return(true)
end

specify do
expect(mx_validator_instance).not_to receive(:hosts_from_cname_records?)
expect(mx_validator_instance).not_to receive(:host_from_a_record?)

expect { mx_validator }
.to change(result_instance, :domain)
.from(nil).to(email[Truemail::RegexConstant::REGEX_EMAIL_PATTERN, 3])
.and not_change(result_instance, :mail_servers)
.and change(result_instance, :success).from(true).to(false)
end

it 'returns false' do
expect(mx_validator).to be(false)
end
end

it 'returns true' do
expect(mx_validator).to be(true)
context 'without null mx' do
before { allow(Resolv).to receive(:getaddresses).and_return([host_address]) }

specify do
expect(mx_validator_instance).to receive(:hosts_from_mx_records?).and_call_original
expect(mx_validator_instance).to receive(:mx_records).and_call_original
expect(mx_validator_instance).to receive(:null_mx?).and_call_original
expect(mx_validator_instance).not_to receive(:hosts_from_cname_records?)
expect(mx_validator_instance).not_to receive(:host_from_a_record?)

expect { mx_validator }
.to change(result_instance, :domain)
.from(nil).to(email[Truemail::RegexConstant::REGEX_EMAIL_PATTERN, 3])
.and change(result_instance, :mail_servers)
.from([]).to(mail_servers_by_ip)
.and not_change(result_instance, :success)
end

it 'returns true' do
expect(mx_validator).to be(true)
end
end
end

Expand Down

0 comments on commit 5a819a8

Please sign in to comment.