Skip to content

Commit e04f255

Browse files
authored
Merge pull request #126 from mocktools/develop
Ruby DnsMock v1.6.0
2 parents 4fe0483 + 2305d7e commit e04f255

File tree

12 files changed

+223
-2
lines changed

12 files changed

+223
-2
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@
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.6.0] - 2024-01-05
6+
7+
### Added
8+
9+
- Added ability to mock SRV records. Thanks [@Siphonay](https://github.com/Siphonay) for feature suggestion
10+
11+
### Updated
12+
13+
- Updated gem version
14+
- Updated gem documentation
15+
516
## [1.5.18] - 2024-01-03
617

718
### Updated

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,16 @@ records = {
8888
},
8989
'1.2.3.4' => { # You can define RDNS host address without lookup prefix. It will be converted to 4.3.2.1.in-addr.arpa automatically
9090
ptr: %w[domain_1.com domain_2.com]
91+
},
92+
'_sip._tcp.example.com' => { # Please use {_service._proto.domain} pattern to follow the valid RFC-2782 SRV host pattern representation
93+
srv: [
94+
{
95+
priority: 0,
96+
weight: 10,
97+
port: 5_060,
98+
target: 'domain.com'
99+
}
100+
]
91101
}
92102
}
93103

lib/dns_mock/core.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
require 'socket'
55

66
module DnsMock
7-
AVAILABLE_DNS_RECORD_TYPES = %i[a aaaa cname mx ns ptr soa txt].freeze
7+
AVAILABLE_DNS_RECORD_TYPES = %i[a aaaa cname mx ns ptr soa srv txt].freeze
88

99
module Error
1010
require_relative '../dns_mock/error/argument_type'
@@ -33,6 +33,7 @@ module Factory
3333
require_relative '../dns_mock/record/factory/ns'
3434
require_relative '../dns_mock/record/factory/ptr'
3535
require_relative '../dns_mock/record/factory/soa'
36+
require_relative '../dns_mock/record/factory/srv'
3637
require_relative '../dns_mock/record/factory/txt'
3738
end
3839
end
@@ -47,6 +48,7 @@ module Builder
4748
require_relative '../dns_mock/record/builder/ns'
4849
require_relative '../dns_mock/record/builder/ptr'
4950
require_relative '../dns_mock/record/builder/soa'
51+
require_relative '../dns_mock/record/builder/srv'
5052
require_relative '../dns_mock/record/builder/txt'
5153
end
5254
end

lib/dns_mock/record/builder/srv.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# frozen_string_literal: true
2+
3+
module DnsMock
4+
module Record
5+
module Builder
6+
class Srv < DnsMock::Record::Builder::Base
7+
FACTORY_ARGS_ORDER = %i[priority weight port target].freeze
8+
9+
def build
10+
records_data.map do |record_data|
11+
target_factory.new(
12+
record_data: record_data.values_at(*DnsMock::Record::Builder::Srv::FACTORY_ARGS_ORDER)
13+
).create
14+
end
15+
end
16+
end
17+
end
18+
end
19+
end

lib/dns_mock/record/factory/srv.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# frozen_string_literal: true
2+
3+
module DnsMock
4+
module Record
5+
module Factory
6+
Srv = ::Class.new(DnsMock::Record::Factory::Base) do
7+
record_type :srv
8+
9+
def instance_params
10+
record_data[0..-2] << create_dns_name(record_data.last)
11+
end
12+
end
13+
end
14+
end
15+
end

lib/dns_mock/server/records_dictionary_builder.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class RecordsDictionaryBuilder
1515
[DnsMock::Record::Builder::Ns, DnsMock::Record::Factory::Ns, ::Array],
1616
[DnsMock::Record::Builder::Ptr, DnsMock::Record::Factory::Ptr, ::Array],
1717
[DnsMock::Record::Builder::Soa, DnsMock::Record::Factory::Soa, ::Array],
18+
[DnsMock::Record::Builder::Srv, DnsMock::Record::Factory::Srv, ::Array],
1819
[DnsMock::Record::Builder::Txt, DnsMock::Record::Factory::Txt, ::Array]
1920
]
2021
).to_h.freeze

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.5.18'
4+
VERSION = '1.6.0'
55
end
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe DnsMock::Record::Builder::Srv do
4+
describe 'class dependencies' do
5+
subject(:builder_class) { described_class }
6+
7+
it { is_expected.to be < DnsMock::Record::Builder::Base }
8+
it { is_expected.to be_const_defined(:FACTORY_ARGS_ORDER) }
9+
end
10+
11+
describe '.call' do
12+
subject(:builder) { described_class.call(target_factory, records_data) }
13+
14+
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) do
18+
(1..8).each_slice(4).map do |chunk|
19+
DnsMock::Record::Builder::Srv::FACTORY_ARGS_ORDER.zip(chunk).to_h
20+
end
21+
end
22+
23+
it 'returns array of target class instances' do
24+
records_data.each do |record_data|
25+
expect(target_factory)
26+
.to receive(:new)
27+
.with(record_data: record_data.values)
28+
.and_return(target_factory_instance)
29+
end
30+
expect(builder).to eq(::Array.new(records_data.size) { target_class_instance })
31+
end
32+
end
33+
end
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe DnsMock::Record::Factory::Srv do
4+
it { expect(described_class).to be < DnsMock::Record::Factory::Base }
5+
6+
describe '#instance_params' do
7+
subject(:instance_params) { described_class.new(record_data: record_data).instance_params }
8+
9+
let(:int_params) { (0..3).to_a }
10+
let(:dns_name) { random_hostname }
11+
let(:record_data) { int_params + [dns_name] }
12+
let(:expected_data) do
13+
[
14+
*int_params,
15+
create_dns_name(dns_name)
16+
]
17+
end
18+
19+
it 'returns prepared target class instance params' do
20+
expect(instance_params).to eq(expected_data)
21+
end
22+
end
23+
24+
describe '#create' do
25+
subject(:create_factory) { described_class.new(record_data: record_data.values).create }
26+
27+
let(:record_data) do
28+
{
29+
priority: 0,
30+
weight: 10,
31+
port: 5_060,
32+
target: target
33+
}
34+
end
35+
36+
context 'when valid record context' do
37+
shared_examples 'returns instance of target class' do
38+
it 'returns instance of target class' do
39+
expect(DnsMock::Representer::Punycode).to receive(:call).with(target).and_call_original
40+
expect(create_factory).to be_an_instance_of(described_class.target_class)
41+
dns_names = record_data.slice(:target).transform_values do |value|
42+
create_dns_name(ascii_hostname ? value : to_punycode_hostname(value))
43+
end
44+
record_data.merge(dns_names).each { |key, value| expect(create_factory.public_send(key)).to eq(value) }
45+
end
46+
end
47+
48+
context 'when ASCII hostname' do
49+
let(:ascii_hostname) { true }
50+
let(:target) { random_hostname }
51+
52+
include_examples 'returns instance of target class'
53+
end
54+
55+
context 'when non ASCII hostname' do
56+
let(:ascii_hostname) { false }
57+
let(:target) { random_non_ascii_hostname }
58+
59+
include_examples 'returns instance of target class'
60+
end
61+
end
62+
63+
context 'when invalid record context' do
64+
context 'when invalid mname' do
65+
let(:target) { 42 }
66+
let(:error_context) { "cannot interpret as DNS name: #{target}. Invalid SRV record context" }
67+
68+
it_behaves_like 'target class exception wrapper'
69+
end
70+
end
71+
end
72+
end

spec/dns_mock_spec.rb

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,27 @@
173173
.and_minimum(soa_record[:minimum])
174174
.config(**rspec_dns_config)
175175
end
176+
177+
it 'returns predefined SRV record' do
178+
srv_record = records_by_domain[:srv].first
179+
180+
expect(domain).to have_dns
181+
.with_type('SRV')
182+
.and_priority(srv_record[:priority])
183+
.config(**rspec_dns_config)
184+
expect(domain).to have_dns
185+
.with_type('SRV')
186+
.and_weight(srv_record[:weight])
187+
.config(**rspec_dns_config)
188+
expect(domain).to have_dns
189+
.with_type('SRV')
190+
.and_port(srv_record[:port])
191+
.config(**rspec_dns_config)
192+
expect(domain).to have_dns
193+
.with_type('SRV')
194+
.and_target(srv_record[:target])
195+
.config(**rspec_dns_config)
196+
end
176197
end
177198

178199
context 'when internationalized records' do
@@ -269,6 +290,27 @@
269290
.and_minimum(soa_record[:minimum])
270291
.config(**rspec_dns_config)
271292
end
293+
294+
it 'returns predefined SRV record' do
295+
srv_record = records_by_domain[:srv].first
296+
297+
expect(domain).to have_dns
298+
.with_type('SRV')
299+
.and_priority(srv_record[:priority])
300+
.config(**rspec_dns_config)
301+
expect(domain).to have_dns
302+
.with_type('SRV')
303+
.and_weight(srv_record[:weight])
304+
.config(**rspec_dns_config)
305+
expect(domain).to have_dns
306+
.with_type('SRV')
307+
.and_port(srv_record[:port])
308+
.config(**rspec_dns_config)
309+
expect(domain).to have_dns
310+
.with_type('SRV')
311+
.and_target(to_punycode_hostname(srv_record[:target]))
312+
.config(**rspec_dns_config)
313+
end
272314
end
273315

274316
context 'when records not found' do

0 commit comments

Comments
 (0)