dns_mock 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.circleci/config.yml +89 -0
- data/.codeclimate.yml +13 -0
- data/.github/BRANCH_NAMING_CONVENTION.md +36 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +28 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +27 -0
- data/.github/ISSUE_TEMPLATE/issue_report.md +28 -0
- data/.github/ISSUE_TEMPLATE/question.md +22 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +49 -0
- data/.gitignore +10 -0
- data/.overcommit.yml +32 -0
- data/.reek.yml +46 -0
- data/.rspec +2 -0
- data/.rubocop.yml +273 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +9 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/CONTRIBUTING.md +46 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +127 -0
- data/LICENSE.txt +21 -0
- data/README.md +79 -0
- data/Rakefile +8 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/dns_mock.gemspec +48 -0
- data/lib/dns_mock.rb +19 -0
- data/lib/dns_mock/core.rb +56 -0
- data/lib/dns_mock/error/argument_type.rb +11 -0
- data/lib/dns_mock/error/helper.rb +22 -0
- data/lib/dns_mock/error/port_in_use.rb +11 -0
- data/lib/dns_mock/error/random_free_port.rb +11 -0
- data/lib/dns_mock/error/record_context.rb +11 -0
- data/lib/dns_mock/error/record_context_type.rb +15 -0
- data/lib/dns_mock/error/record_host_type.rb +11 -0
- data/lib/dns_mock/error/record_not_found.rb +11 -0
- data/lib/dns_mock/error/record_type.rb +11 -0
- data/lib/dns_mock/record/builder/a.rb +9 -0
- data/lib/dns_mock/record/builder/aaaa.rb +9 -0
- data/lib/dns_mock/record/builder/base.rb +26 -0
- data/lib/dns_mock/record/builder/cname.rb +13 -0
- data/lib/dns_mock/record/builder/mx.rb +22 -0
- data/lib/dns_mock/record/builder/ns.rb +9 -0
- data/lib/dns_mock/record/builder/soa.rb +19 -0
- data/lib/dns_mock/record/builder/txt.rb +9 -0
- data/lib/dns_mock/record/factory/a.rb +15 -0
- data/lib/dns_mock/record/factory/aaaa.rb +15 -0
- data/lib/dns_mock/record/factory/base.rb +54 -0
- data/lib/dns_mock/record/factory/cname.rb +15 -0
- data/lib/dns_mock/record/factory/mx.rb +15 -0
- data/lib/dns_mock/record/factory/ns.rb +15 -0
- data/lib/dns_mock/record/factory/soa.rb +15 -0
- data/lib/dns_mock/record/factory/txt.rb +15 -0
- data/lib/dns_mock/response/answer.rb +32 -0
- data/lib/dns_mock/response/message.rb +29 -0
- data/lib/dns_mock/server.rb +82 -0
- data/lib/dns_mock/server/random_available_port.rb +48 -0
- data/lib/dns_mock/server/records_dictionary_builder.rb +52 -0
- data/lib/dns_mock/version.rb +5 -0
- metadata +334 -0
data/lib/dns_mock.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'dns_mock/core'
|
4
|
+
|
5
|
+
module DnsMock
|
6
|
+
class << self
|
7
|
+
def start_server(server = DnsMock::Server, records: {}, port: nil)
|
8
|
+
server.new(records: records, port: port)
|
9
|
+
end
|
10
|
+
|
11
|
+
def running_servers
|
12
|
+
::ObjectSpace.each_object(DnsMock::Server).select(&:alive?)
|
13
|
+
end
|
14
|
+
|
15
|
+
def stop_running_servers!
|
16
|
+
running_servers.all?(&:stop!)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'resolv'
|
4
|
+
require 'socket'
|
5
|
+
|
6
|
+
module DnsMock
|
7
|
+
AVAILABLE_DNS_RECORD_TYPES = %i[a aaaa cname mx ns soa txt].freeze
|
8
|
+
|
9
|
+
module Error
|
10
|
+
require_relative '../dns_mock/error/argument_type'
|
11
|
+
require_relative '../dns_mock/error/port_in_use'
|
12
|
+
require_relative '../dns_mock/error/random_free_port'
|
13
|
+
require_relative '../dns_mock/error/record_context_type'
|
14
|
+
require_relative '../dns_mock/error/record_context'
|
15
|
+
require_relative '../dns_mock/error/record_host_type'
|
16
|
+
require_relative '../dns_mock/error/record_not_found'
|
17
|
+
require_relative '../dns_mock/error/record_type'
|
18
|
+
require_relative '../dns_mock/error/helper'
|
19
|
+
end
|
20
|
+
|
21
|
+
module Record
|
22
|
+
module Factory
|
23
|
+
require_relative '../dns_mock/record/factory/base'
|
24
|
+
require_relative '../dns_mock/record/factory/a'
|
25
|
+
require_relative '../dns_mock/record/factory/aaaa'
|
26
|
+
require_relative '../dns_mock/record/factory/cname'
|
27
|
+
require_relative '../dns_mock/record/factory/mx'
|
28
|
+
require_relative '../dns_mock/record/factory/ns'
|
29
|
+
require_relative '../dns_mock/record/factory/soa'
|
30
|
+
require_relative '../dns_mock/record/factory/txt'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module Record
|
35
|
+
module Builder
|
36
|
+
require_relative '../dns_mock/record/builder/base'
|
37
|
+
require_relative '../dns_mock/record/builder/a'
|
38
|
+
require_relative '../dns_mock/record/builder/aaaa'
|
39
|
+
require_relative '../dns_mock/record/builder/cname'
|
40
|
+
require_relative '../dns_mock/record/builder/mx'
|
41
|
+
require_relative '../dns_mock/record/builder/ns'
|
42
|
+
require_relative '../dns_mock/record/builder/soa'
|
43
|
+
require_relative '../dns_mock/record/builder/txt'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
module Response
|
48
|
+
require_relative '../dns_mock/response/answer'
|
49
|
+
require_relative '../dns_mock/response/message'
|
50
|
+
end
|
51
|
+
|
52
|
+
require_relative '../dns_mock/version'
|
53
|
+
require_relative '../dns_mock/server/records_dictionary_builder'
|
54
|
+
require_relative '../dns_mock/server/random_available_port'
|
55
|
+
require_relative '../dns_mock/server'
|
56
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DnsMock
|
4
|
+
module Error
|
5
|
+
module Helper
|
6
|
+
def raise_record_context_type_error(record_type, record_context, expected_type)
|
7
|
+
current_type, record_type = record_context.class, record_type.upcase
|
8
|
+
raise_unless(DnsMock::Error::RecordContextType.new(current_type, record_type, expected_type), current_type.eql?(expected_type))
|
9
|
+
end
|
10
|
+
|
11
|
+
def raise_record_type_error(record_type, condition)
|
12
|
+
raise_unless(DnsMock::Error::RecordType.new(record_type), condition)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def raise_unless(error_instance, condition)
|
18
|
+
raise error_instance unless condition
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DnsMock
|
4
|
+
module Error
|
5
|
+
PortInUse = ::Class.new(::RuntimeError) do
|
6
|
+
def initialize(hostname, port)
|
7
|
+
super("Impossible to bind UDP DNS mock server on #{hostname}:#{port}. Address already in use")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DnsMock
|
4
|
+
module Error
|
5
|
+
RecordContextType = ::Class.new(::ArgumentError) do
|
6
|
+
def initialize(record_context_type, record_type, expected_record_context_type)
|
7
|
+
super(
|
8
|
+
"#{record_context_type} is invalid record context type for " \
|
9
|
+
"#{record_type} record. Should be a " \
|
10
|
+
"#{expected_record_context_type}"
|
11
|
+
)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DnsMock
|
4
|
+
module Error
|
5
|
+
RecordHostType = ::Class.new(::ArgumentError) do
|
6
|
+
def initialize(hostname, hostname_class)
|
7
|
+
super("Hostname #{hostname} type is #{hostname_class}. Should be a String")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DnsMock
|
4
|
+
module Error
|
5
|
+
RecordNotFound = ::Class.new(::StandardError) do
|
6
|
+
def initialize(record_type, hostname)
|
7
|
+
super("#{record_type.upcase} record not found for #{hostname} in predefined records dictionary")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DnsMock
|
4
|
+
module Record
|
5
|
+
module Builder
|
6
|
+
class Base
|
7
|
+
def self.call(target_factory, records_data)
|
8
|
+
new(target_factory, records_data).build
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(target_factory, records_data)
|
12
|
+
@target_factory = target_factory
|
13
|
+
@records_data = records_data
|
14
|
+
end
|
15
|
+
|
16
|
+
def build
|
17
|
+
records_data.map { |record_data| target_factory.new(record_data: record_data).create }
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
attr_reader :target_factory, :records_data
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DnsMock
|
4
|
+
module Record
|
5
|
+
module Builder
|
6
|
+
class Mx < DnsMock::Record::Builder::Base
|
7
|
+
RECORD_PREFERENCE_STEP = 10
|
8
|
+
|
9
|
+
def build
|
10
|
+
records_data.map.with_index(1) do |record_data, record_preference|
|
11
|
+
target_factory.new(
|
12
|
+
record_data: [
|
13
|
+
record_preference * DnsMock::Record::Builder::Mx::RECORD_PREFERENCE_STEP,
|
14
|
+
record_data
|
15
|
+
]
|
16
|
+
).create
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DnsMock
|
4
|
+
module Record
|
5
|
+
module Builder
|
6
|
+
class Soa < DnsMock::Record::Builder::Base
|
7
|
+
FACTORY_ARGS_ORDER = %i[mname rname serial refresh retry expire minimum].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::Soa::FACTORY_ARGS_ORDER)
|
13
|
+
).create
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DnsMock
|
4
|
+
module Record
|
5
|
+
module Factory
|
6
|
+
class Base
|
7
|
+
extend DnsMock::Error::Helper
|
8
|
+
|
9
|
+
class << self
|
10
|
+
attr_reader :target_class
|
11
|
+
|
12
|
+
def record_type(record_type)
|
13
|
+
@target_class = ::Resolv::DNS::Resource::IN.const_get(
|
14
|
+
record_type_check(record_type).upcase
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def record_type_check(defined_record_type)
|
21
|
+
raise_record_type_error(defined_record_type, DnsMock::AVAILABLE_DNS_RECORD_TYPES.include?(defined_record_type))
|
22
|
+
defined_record_type
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(dns_name = ::Resolv::DNS::Name, record_data:)
|
27
|
+
@dns_name = dns_name
|
28
|
+
@record_data = record_data
|
29
|
+
end
|
30
|
+
|
31
|
+
def instance_params; end
|
32
|
+
|
33
|
+
def create
|
34
|
+
self.class.target_class.public_send(:new, *instance_params)
|
35
|
+
rescue => error
|
36
|
+
raise DnsMock::Error::RecordContext.new(error.message, record_type)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
attr_reader :dns_name, :record_data
|
42
|
+
|
43
|
+
def record_type
|
44
|
+
self.class.name.split('::').last.upcase
|
45
|
+
end
|
46
|
+
|
47
|
+
def create_dns_name(hostname)
|
48
|
+
raise ::ArgumentError, "cannot interpret as DNS name: #{hostname}" unless hostname.is_a?(::String)
|
49
|
+
dns_name.create("#{hostname}.")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DnsMock
|
4
|
+
module Record
|
5
|
+
module Factory
|
6
|
+
Cname = ::Class.new(DnsMock::Record::Factory::Base) do
|
7
|
+
record_type :cname
|
8
|
+
|
9
|
+
def instance_params
|
10
|
+
[create_dns_name(record_data)]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DnsMock
|
4
|
+
module Record
|
5
|
+
module Factory
|
6
|
+
Mx = ::Class.new(DnsMock::Record::Factory::Base) do
|
7
|
+
record_type :mx
|
8
|
+
|
9
|
+
def instance_params
|
10
|
+
[record_data.first, create_dns_name(record_data.last)]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|