diff --git a/app/services/check_domain_processor.rb b/app/services/check_domain_processor.rb new file mode 100644 index 0000000..356e5aa --- /dev/null +++ b/app/services/check_domain_processor.rb @@ -0,0 +1,25 @@ +class CheckDomainProcessor + include CheckProcessor + protected + + def configuration_key + "checks_domain" + end + + def resolvers + %i[ + resolve_last_run_failed + resolve_expire_short_term + resolve_expire_long_term + resolve_unknown_expiry + ] + end + + def scope + base_scope.domain + end + + def process(check) + WhoisSyncJob.perform_now(check.id) + end +end diff --git a/app/services/check_processor.rb b/app/services/check_processor.rb index 31737c3..15c1e2e 100644 --- a/app/services/check_processor.rb +++ b/app/services/check_processor.rb @@ -1,17 +1,12 @@ -class CheckProcessor +module CheckProcessor attr_reader :configuration def initialize(configuration = nil) @configuration = configuration || default_configuration end - def sync_dates # rubocop:disable Metrics/MethodLength - %i[ - resolve_last_run_failed - resolve_expire_short_term - resolve_expire_long_term - resolve_unknown_expiry - ].each do |resolver| + def sync_dates + resolvers.each do |resolver| public_send(resolver).find_each(batch_size: 100).each do |check| process(check) @@ -20,6 +15,12 @@ class CheckProcessor end end + # :nocov: + def resolvers + fail NotImplementedError, "#{self.class.name} did not implemented method #{__callee__}" + end + # :nocov: + def resolve_last_run_failed scope.last_run_failed end @@ -41,25 +42,32 @@ class CheckProcessor scope.where("domain_expires_at IS NULL") end - private + protected - def scope + def base_scope Check .active .where("last_run_at IS NULL OR last_run_at < DATE_SUB(NOW(), INTERVAL 12 HOUR)") end - def process(check) - case check.kind.to_sym - when :domain - WhoisSyncJob.perform_now(check.id) - else - fail ArgumentError, "Unsupported check kind `#{check.kind}`" - end + # :nocov: + def scope + fail NotImplementedError, "#{self.class.name} did not implemented method #{__callee__}" end + def process(check) + fail NotImplementedError, "#{self.class.name} did not implemented method #{__callee__}" + end + + def configuration_key + fail NotImplementedError, "#{self.class.name} did not implemented method #{__callee__}" + end + # :nocov: + + private + def default_configuration - config = Rails.configuration.chexpire.fetch("checks", {}) + config = Rails.configuration.chexpire.fetch(configuration_key, {}) OpenStruct.new( interval: config.fetch("interval") { 0.00 }, diff --git a/config/chexpire.example.yml b/config/chexpire.example.yml index ffb7daa..1daaa4a 100644 --- a/config/chexpire.example.yml +++ b/config/chexpire.example.yml @@ -3,7 +3,7 @@ default: &default notifier: interval: 0.00 failure_days: 3 - checks: + checks_domain: interval: 0.5 long_term: 60 long_term_frequency: 10 diff --git a/config/chexpire.test.yml b/config/chexpire.test.yml index db88e9a..dc99552 100644 --- a/config/chexpire.test.yml +++ b/config/chexpire.test.yml @@ -4,7 +4,7 @@ test: notifier: interval: 0.00 failure_days: 3 - checks: + checks_domain: interval: 0.00 long_term: 60 long_term_frequency: 10 diff --git a/config/schedule.rb b/config/schedule.rb index 709286e..27553b1 100644 --- a/config/schedule.rb +++ b/config/schedule.rb @@ -19,7 +19,7 @@ set :output, standard: "log/cron.log" # Learn more: http://github.com/javan/whenever every 1.day, at: '4:30 am', roles: [:app] do - rake "checks:sync_dates" + rake "checks:sync_dates:all" end every 1.day, at: '10:30 am', roles: [:app] do diff --git a/lib/tasks/checks.rake b/lib/tasks/checks.rake index 5d82236..a37eb60 100644 --- a/lib/tasks/checks.rake +++ b/lib/tasks/checks.rake @@ -1,7 +1,11 @@ namespace :checks do - desc "Refresh expiry dates for checks" - task sync_dates: :environment do - process = CheckProcessor.new - process.sync_dates + namespace :sync_dates do + task all: [:domain] + + desc "Refresh domains expiry dates" + task domain: :environment do + process = CheckDomainProcessor.new + process.sync_dates + end end end diff --git a/test/factories/checks.rb b/test/factories/checks.rb index 62d95ec..f940eb2 100644 --- a/test/factories/checks.rb +++ b/test/factories/checks.rb @@ -44,6 +44,10 @@ FactoryBot.define do kind :domain end + trait :ssl do + kind :ssl + end + trait :nil_dates do domain_created_at nil domain_updated_at nil diff --git a/test/services/check_domain_processor_test.rb b/test/services/check_domain_processor_test.rb new file mode 100644 index 0000000..1ea3023 --- /dev/null +++ b/test/services/check_domain_processor_test.rb @@ -0,0 +1,34 @@ +require "test_helper" + +class CheckDomainProcessorTest < ActiveSupport::TestCase + setup do + @processor = CheckDomainProcessor.new + end + + test "process WhoisSyncJob for domain checks" do + domain = "domain.fr" + check = create(:check, :domain, :nil_dates, domain: domain) + + mock_system_command("whois", domain, stdout: file_fixture("whois/domain.fr.txt").read) do + @processor.send(:process, check) + end + + check.reload + + assert_equal Time.new(2019, 2, 17, 0, 0, 0, 0), check.domain_expires_at + end + + test "scope concerns only checks of kind 'domain'" do + domains = create_list(:check, 2, :domain) + create_list(:check, 2, :ssl) + + assert_equal domains, @processor.send(:scope) + end + + test "resolvers returns an array of methods returning a scope" do + assert_not_empty @processor.send(:resolvers) + @processor.send(:resolvers).each do |method| + assert_kind_of ActiveRecord::Relation, @processor.public_send(method) + end + end +end diff --git a/test/services/check_processor_test.rb b/test/services/check_processor_test.rb index 66e1e53..9751ec5 100644 --- a/test/services/check_processor_test.rb +++ b/test/services/check_processor_test.rb @@ -1,31 +1,26 @@ require "test_helper" +class CheckDummyProcessor + include CheckProcessor + def scope + base_scope + end + + def configuration_key + "checks_dummy" + end + + def resolvers + %i[ + resolve_expire_short_term + resolve_expire_long_term + ] + end +end + class CheckProcessorTest < ActiveSupport::TestCase setup do - @processor = CheckProcessor.new - end - - test "process WhoisSyncJob for domain checks" do - domain = "domain.fr" - check = create(:check, :domain, :nil_dates, domain: domain) - - mock_system_command("whois", domain, stdout: file_fixture("whois/domain.fr.txt").read) do - @processor.send(:process, check) - end - - check.reload - - assert_equal Time.new(2019, 2, 17, 0, 0, 0, 0), check.domain_expires_at - end - - test "raises an error for an unsupported check kind" do - check = build(:check) - - check.stub :kind, :unknown do - assert_raises ArgumentError do - @processor.send(:process, check) - end - end + @processor = CheckDummyProcessor.new end test "resolve_last_run_failed includes already and never succeeded" do @@ -113,7 +108,7 @@ class CheckProcessorTest < ActiveSupport::TestCase configuration.expect(:interval, 0.000001) end - processor = CheckProcessor.new(configuration) + processor = CheckDummyProcessor.new(configuration) mock = Minitest::Mock.new assert_stub = lambda { |actual_time|