diff --git a/.circleci/config.yml b/.circleci/config.yml index cf0cb7f..d25cd66 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -67,6 +67,10 @@ jobs: - <<: *bundle_install - <<: *install_linters + - run: + name: Running commit linters + command: lefthook run commit-linters + - run: name: Running code style linters command: lefthook run code-style-linters diff --git a/.circleci/gemspecs/latest b/.circleci/gemspecs/latest index 63f0230..f7a7f0a 100644 --- a/.circleci/gemspecs/latest +++ b/.circleci/gemspecs/latest @@ -25,7 +25,7 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'pry-byebug', '~> 3.10', '>= 3.10.1' spec.add_development_dependency 'rake', '~> 13.1' spec.add_development_dependency 'reek', '~> 6.3' - spec.add_development_dependency 'rspec', '~> 3.12' + spec.add_development_dependency 'rspec', '~> 3.13' spec.add_development_dependency 'rspec-dns', '~> 0.1.8' spec.add_development_dependency 'rubocop', '~> 1.60', '>= 1.60.2' spec.add_development_dependency 'rubocop-performance', '~> 1.20', '>= 1.20.2' diff --git a/.circleci/linter_configs/.commitspell.yml b/.circleci/linter_configs/.commitspell.yml new file mode 100644 index 0000000..d5b1801 --- /dev/null +++ b/.circleci/linter_configs/.commitspell.yml @@ -0,0 +1,41 @@ +--- + +enableGlobDot: true + +patterns: + - name: GithubUser + pattern: /\[@.+\]/gmx + +languageSettings: + - languageId: markdown + ignoreRegExpList: + - Email + - GithubUser + +words: + - bagage + - bagages + - bestwebua + - changeloglint + - configurator + - codebases + - codeclimate + - commitspell + - ffaker + - gemspecs + - hostnames + - lefthook + - markdownlint + - mocktools + - mroach + - mdlrc + - punycode + - rubocop + - representer + - rdns + - shortcuting + - simplecov + - simpleidn + - stdlib + - substeps + - yamlint diff --git a/.circleci/linter_configs/.lefthook.yml b/.circleci/linter_configs/.lefthook.yml index 05407a5..adc407b 100644 --- a/.circleci/linter_configs/.lefthook.yml +++ b/.circleci/linter_configs/.lefthook.yml @@ -4,6 +4,11 @@ no_tty: true skip_output: - meta +commit-linters: + commands: + commitspell: + run: .circleci/scripts/commitspell.sh -c '.circleci/linter_configs/.commitspell.yml' + code-style-linters: commands: reek: diff --git a/.circleci/scripts/commitspell.sh b/.circleci/scripts/commitspell.sh new file mode 100755 index 0000000..d284cd0 --- /dev/null +++ b/.circleci/scripts/commitspell.sh @@ -0,0 +1,22 @@ +#!/bin/sh +set -e + +configuration=$(if [ "$2" = "" ]; then echo "$2"; else echo " $1 $2"; fi) +latest_commit=$(git rev-parse HEAD) + +spellcheck_info() { + echo "Checking the spelling of the latest commit ($latest_commit) message..." +} + +compose_cspell_command() { + echo "cspell-cli lint stdin$configuration" +} + +cspell="$(compose_cspell_command)" + +spellcheck_latest_commit() { + git log -1 --pretty=%B | $cspell +} + +spellcheck_info +spellcheck_latest_commit diff --git a/CHANGELOG.md b/CHANGELOG.md index e7446c4..8256def 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,17 @@ 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). +## [1.7.0] - 2024-04-18 + +### Added + +- Added ability to interact with DNS message question/answer context. Thanks [@mroach](https://github.com/mroach) for feature suggestion and PR + +### Updated + +- Updated gem documentation +- Updated gem version + ## [1.6.2] - 2024-01-31 ### Added diff --git a/README.md b/README.md index 6239dce..b9adee2 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,10 @@ dns_mock_server = DnsMock.start_server(records: records) # => DnsMock::Server in # returns current dns mock server port dns_mock_server.port # => 49322 +# returns current collected server lookup messsages +# represented as array of Resolv::DNS::Message instances +dns_mock_server.messages # => [#] + # interface to setup mock records. # Available only in case when server mocked records is empty dns_mock_server.assign_mocks(records) # => true/nil @@ -122,6 +126,9 @@ dns_mock_server.assign_mocks(records) # => true/nil # interface to reset current mocked records dns_mock_server.reset_mocks! # => true +# interface to clear collected lookup messages +dns_mock_server.clear_messages! # => true + # interface to stop current dns mock server dns_mock_server.stop! # => true @@ -192,10 +199,11 @@ end If you won't use `DnsMock::TestFramework::RSpec::Helper` you can use `DnsMock::TestFramework::RSpec::Interface` directly instead: ```ruby -DnsMock::TestFramework::RSpec::Interface.start_server # creates and runs DnsMock server instance -DnsMock::TestFramework::RSpec::Interface.stop_server! # stops current DnsMock server instance -DnsMock::TestFramework::RSpec::Interface.reset_mocks! # resets mocks in current DnsMock server instance -DnsMock::TestFramework::RSpec::Interface.clear_server! # stops and clears current DnsMock server instance +DnsMock::TestFramework::RSpec::Interface.start_server # creates and runs DnsMock server instance +DnsMock::TestFramework::RSpec::Interface.stop_server! # stops current DnsMock server instance +DnsMock::TestFramework::RSpec::Interface.reset_mocks! # resets mocks in current DnsMock server instance +DnsMock::TestFramework::RSpec::Interface.clear_messages! # clears collected lookup messages in current DnsMock server instance +DnsMock::TestFramework::RSpec::Interface.clear_server! # stops and clears current DnsMock server instance ``` ## Contributing diff --git a/dns_mock.gemspec b/dns_mock.gemspec index c09c3c0..5fde804 100644 --- a/dns_mock.gemspec +++ b/dns_mock.gemspec @@ -34,6 +34,6 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'ffaker', ffaker_version spec.add_development_dependency 'net-ftp', '~> 0.3.4' if current_ruby_version >= ::Gem::Version.new('3.1.0') spec.add_development_dependency 'rake', '~> 13.1' - spec.add_development_dependency 'rspec', '~> 3.12' + spec.add_development_dependency 'rspec', '~> 3.13' spec.add_development_dependency 'rspec-dns', '~> 0.1.8' end diff --git a/lib/dns_mock/response/message.rb b/lib/dns_mock/response/message.rb index b29289b..825b4df 100644 --- a/lib/dns_mock/response/message.rb +++ b/lib/dns_mock/response/message.rb @@ -3,6 +3,8 @@ module DnsMock module Response class Message + attr_reader :dns_message + def initialize( packet, records, @@ -23,7 +25,7 @@ def as_binary_string private - attr_reader :dns_answer, :dns_message + attr_reader :dns_answer def compose_answer dns_message.each_question do |hostname, record_type| diff --git a/lib/dns_mock/server.rb b/lib/dns_mock/server.rb index 9cf85d6..3d9fb8d 100644 --- a/lib/dns_mock/server.rb +++ b/lib/dns_mock/server.rb @@ -9,7 +9,7 @@ class Server WARMUP_DELAY = 0.1 PACKET_MAX_BYTES_SIZE = 65_535 - attr_reader :port + attr_reader :port, :messages def initialize( # rubocop:disable Metrics/ParameterLists socket = ::UDPSocket.new, @@ -25,10 +25,11 @@ def initialize( # rubocop:disable Metrics/ParameterLists @records = records_dictionary_builder.call(records || {}) @port = port || 0 @exception_if_not_found = exception_if_not_found + @messages = [] prepare_server_thread end - def run + def run # rubocop:disable Metrics/AbcSize prepare_socket_for_session update_server_port @@ -38,7 +39,9 @@ def run break if packet.empty? address, port = addr.values_at(3, 1) - socket.send(DnsMock::Response::Message.new(packet, records, exception_if_not_found).as_binary_string, 0, address, port) + message = DnsMock::Response::Message.new(packet, records, exception_if_not_found) + socket.send(message.as_binary_string, 0, address, port) + messages.push(message.dns_message) end ensure socket.close @@ -53,6 +56,10 @@ def reset_mocks! records.clear.empty? end + def clear_messages! + !!messages.clear + end + def without_mocks? records.empty? end diff --git a/lib/dns_mock/version.rb b/lib/dns_mock/version.rb index 39e1af4..316055d 100644 --- a/lib/dns_mock/version.rb +++ b/lib/dns_mock/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module DnsMock - VERSION = '1.6.2' + VERSION = '1.7.0' end diff --git a/spec/dns_mock/server_spec.rb b/spec/dns_mock/server_spec.rb index a6203b9..ffb3453 100644 --- a/spec/dns_mock/server_spec.rb +++ b/spec/dns_mock/server_spec.rb @@ -156,6 +156,24 @@ end end + describe '#clear_messages!' do + subject(:clear_messages) { server_instance.clear_messages! } + + let(:server_instance) { described_class.new } + let(:message) { instance_double('SomeServerMessage') } + + before { server_instance.messages << message } + + it 'erases all server messages' do + expect { clear_messages } + .to change(server_instance, :messages) + .from([message]) + .to([]) + expect(clear_messages).to be(true) + expect(server_instance.messages).to be_empty + end + end + describe '#without_mocks?' do subject(:without_mocks) { server_instance.without_mocks? } diff --git a/spec/dns_mock_spec.rb b/spec/dns_mock_spec.rb index 2c2d580..0ba8d06 100644 --- a/spec/dns_mock_spec.rb +++ b/spec/dns_mock_spec.rb @@ -74,8 +74,7 @@ let(:port) { 5300 } let(:ip_address) { random_ip_v4_address } let(:rspec_dns_config) { { nameserver: 'localhost', port: port } } - - before { described_class.start_server(records: records, port: port) } + let!(:server_instance) { described_class.start_server(records: records, port: port) } after { stop_all_running_servers } @@ -172,6 +171,7 @@ .with_type('SOA') .and_minimum(soa_record[:minimum]) .config(**rspec_dns_config) + expect(server_instance.messages.size).to eq(7) end it 'returns predefined SRV record' do @@ -193,6 +193,7 @@ .with_type('SRV') .and_target(srv_record[:target]) .config(**rspec_dns_config) + expect(server_instance.messages.size).to eq(4) end end @@ -289,6 +290,7 @@ .with_type('SOA') .and_minimum(soa_record[:minimum]) .config(**rspec_dns_config) + expect(server_instance.messages.size).to eq(7) end it 'returns predefined SRV record' do @@ -310,6 +312,7 @@ .with_type('SRV') .and_target(to_punycode_hostname(srv_record[:target])) .config(**rspec_dns_config) + expect(server_instance.messages.size).to eq(4) end end @@ -321,6 +324,9 @@ .with_type('A') .and_address(random_ip_v4_address) .config(**rspec_dns_config) + dns_message = server_instance.messages.first + expect(dns_message).to be_an_instance_of(::Resolv::DNS::Message) + expect(dns_message.answer).to be_empty end end end