Skip to content

Commit eed50bc

Browse files
authored
Feature/Ability to specify MX record priority (#30)
* Updated DnsMock::Record::Builder::Mx, tests * Updated gem version, readme, changelog
1 parent 819726d commit eed50bc

File tree

7 files changed

+111
-17
lines changed

7 files changed

+111
-17
lines changed

.reek.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,7 @@ detectors:
5353
exclude:
5454
- DnsMock::Server#initialize
5555
- DnsMock#start_server
56+
57+
NilCheck:
58+
exclude:
59+
- DnsMock::Record::Builder::Mx#build

CHANGELOG.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,41 @@
22

33
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
44

5+
## [1.2.0] - 2021-02-04
6+
7+
### Ability to specify MX record priority
8+
9+
Added ability to specify custom priority of MX record if it needed. Now it impossible to define null or backup MX records. Please note, if you haven't specified a priority of MX record, it will be assigned automatically. MX records builder is assigning priority with step 10 from first item of defined MX records array.
10+
11+
```ruby
12+
records = {
13+
'example.com' => {
14+
mx: %w[.:0 mx1.domain.com:10 mx2.domain.com:10 mx3.domain.com]
15+
}
16+
}
17+
18+
DnsMock.start_server(records: records)
19+
```
20+
21+
```bash
22+
dig @localhost -p 5300 MX example.com
23+
```
24+
25+
```
26+
; <<>> DiG 9.10.6 <<>> @localhost -p 5300 MX example.com
27+
28+
;; ANSWER SECTION:
29+
example.com. 1 IN MX 0 .
30+
example.com. 1 IN MX 10 mx1.domain.com.
31+
example.com. 1 IN MX 10 mx2.domain.com.
32+
example.com. 1 IN MX 40 mx3.domain.com.
33+
34+
;; Query time: 0 msec
35+
;; SERVER: 127.0.0.1#5300(127.0.0.1)
36+
;; WHEN: Wed Feb 03 20:19:51 EET 2021
37+
;; MSG SIZE rcvd: 102
38+
```
39+
540
## [1.1.0] - 2021-02-01
641

742
### RSpec native support

Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
PATH
22
remote: .
33
specs:
4-
dns_mock (1.1.0)
4+
dns_mock (1.2.0)
55

66
GEM
77
remote: https://rubygems.org/

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,13 @@ Or install it yourself as:
5757
## Usage
5858

5959
```ruby
60-
# Example of mocked DNS records structure
60+
# Example of mocked DNS records, please follow this data structure
6161
records = {
6262
'example.com' => {
6363
a: %w[1.1.1.1 2.2.2.2],
6464
aaaa: %w[2a00:1450:4001:81e::200e],
6565
ns: %w[ns1.domain.com ns2.domain.com],
66-
mx: %w[mx1.domain.com mx2.domain.com],
66+
mx: %w[mx1.domain.com mx2.domain.com:50], # you can specify host(s) or host(s) with priority
6767
txt: %w[txt_record_1 txt_record_2],
6868
cname: 'some.domain.com',
6969
soa: [
@@ -132,7 +132,7 @@ require 'dns_mock/test_framework/rspec'
132132

133133
#### DnsMock RSpec helper
134134

135-
Just add `DnsMock::TestFramework::RSpec::Helper` if you wanna have shortcut for DnsMock server instance into your RSpec.describe blocks:
135+
Just add `DnsMock::TestFramework::RSpec::Helper` if you wanna use shortcut `dns_mock_server` for DnsMock server instance into your `RSpec.describe` blocks:
136136

137137
```ruby
138138
# spec/support/config/dns_mock.rb

lib/dns_mock/record/builder/mx.rb

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,29 @@ module DnsMock
44
module Record
55
module Builder
66
class Mx < DnsMock::Record::Builder::Base
7+
include DnsMock::Error::Helper
8+
9+
MX_RECORD_REGEX_PATTERN = /\A(.+):(\d+)|(.+)\z/.freeze
710
RECORD_PREFERENCE_STEP = 10
811

912
def build
1013
records_data.map.with_index(1) do |record_data, record_preference|
14+
record_data, custom_record_preference = parse_mx_record_data(record_data)
1115
target_factory.new(
1216
record_data: [
13-
record_preference * DnsMock::Record::Builder::Mx::RECORD_PREFERENCE_STEP,
17+
custom_record_preference&.to_i || record_preference * DnsMock::Record::Builder::Mx::RECORD_PREFERENCE_STEP,
1418
record_data
1519
]
1620
).create
1721
end
1822
end
23+
24+
private
25+
26+
def parse_mx_record_data(record_data)
27+
raise_record_context_type_error(:mx, record_data, ::String)
28+
record_data.scan(DnsMock::Record::Builder::Mx::MX_RECORD_REGEX_PATTERN).flatten.compact
29+
end
1930
end
2031
end
2132
end

lib/dns_mock/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# frozen_string_literal: true
22

33
module DnsMock
4-
VERSION = '1.1.0'
4+
VERSION = '1.2.0'
55
end

spec/dns_mock/record/builder/mx_spec.rb

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,69 @@
55
subject(:builder_class) { described_class }
66

77
it { is_expected.to be < DnsMock::Record::Builder::Base }
8+
it { is_expected.to be_const_defined(:MX_RECORD_REGEX_PATTERN) }
89
it { is_expected.to be_const_defined(:RECORD_PREFERENCE_STEP) }
910
end
1011

12+
describe 'MX_RECORD_REGEX_PATTERN' do
13+
subject(:regex_pattern) { described_class::MX_RECORD_REGEX_PATTERN }
14+
15+
context 'when host with priority' do
16+
subject(:string) { "#{host}:#{priority}" }
17+
18+
let(:host) { random_hostname }
19+
let(:priority) { rand(100).to_s }
20+
21+
it { expect(regex_pattern.match?(string)).to be(true) }
22+
it { expect(string[regex_pattern, 1]).to eq(host) }
23+
it { expect(string[regex_pattern, 2]).to eq(priority) }
24+
end
25+
26+
context 'when host without priority' do
27+
subject(:string) { random_hostname }
28+
29+
it { expect(regex_pattern.match?(string)).to be(true) }
30+
it { expect(string[regex_pattern, 3]).to eq(string) }
31+
end
32+
end
33+
1134
describe '.call' do
1235
subject(:builder) { described_class.call(target_factory, records_data) }
1336

1437
let(:target_factory) { class_double('TargetFactory') }
15-
let(:target_class_instance) { instance_double('TargetClass') }
16-
let(:target_factory_instance) { instance_double('TargetFactory', create: target_class_instance) }
17-
let(:records_data) { (0..2) }
18-
19-
it 'returns array of target class instances' do
20-
[10, 20, 30].zip(records_data).each do |record_preference, record_data|
21-
expect(target_factory)
22-
.to receive(:new)
23-
.with(record_data: [record_preference, record_data])
24-
.and_return(target_factory_instance)
38+
39+
describe 'Success' do
40+
context 'when valid records_data nested type' do
41+
let(:target_class_instance) { instance_double('TargetClass') }
42+
let(:target_factory_instance) { instance_double('TargetFactory', create: target_class_instance) }
43+
let(:mx_host) { random_hostname }
44+
let(:mx_priority) { 0 }
45+
let(:records_data) { ["#{mx_host}:#{mx_priority}", 'b', 'c'] }
46+
47+
it 'returns array of target class instances' do
48+
[10, 20, 30].zip(records_data).each_with_index do |(record_preference, record_data), index|
49+
expect(target_factory)
50+
.to receive(:new)
51+
.with(record_data: index.zero? ? [mx_priority, mx_host] : [record_preference, record_data])
52+
.and_return(target_factory_instance)
53+
end
54+
expect(builder).to eq(::Array.new(records_data.size) { target_class_instance })
55+
end
56+
end
57+
end
58+
59+
describe 'Failure' do
60+
context 'when invalid records_data nested type' do
61+
let(:record_data_object) { 42 }
62+
let(:records_data) { [record_data_object] }
63+
64+
it do
65+
expect { builder }.to raise_error(
66+
DnsMock::Error::RecordContextType,
67+
"#{record_data_object.class} is invalid record context type for MX record. Should be a String"
68+
)
69+
end
2570
end
26-
expect(builder).to eq(::Array.new(records_data.size) { target_class_instance })
2771
end
2872
end
2973
end

0 commit comments

Comments
 (0)