diff --git a/.travis.yml b/.travis.yml index a690b21..6191048 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,9 +13,12 @@ addons: before_install: - cp config/database.example.yml config/database.yml - - cp config/chexpire.test.yml config/chexpire.yml - cp config/secrets.example.yml config/secrets.yml + # Test configuration loaded from chexpire.defaults.yml, + # but chexpire.yml file is required + - touch config/chexpire.yml + install: - bundle install - yarn install diff --git a/Gemfile b/Gemfile index e3665cb..14530c2 100644 --- a/Gemfile +++ b/Gemfile @@ -38,6 +38,7 @@ gem 'bcrypt', '~> 3.1.7' gem 'open4' gem 'naught' +gem 'hashie' gem 'whenever', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 5e091d7..ff2fd77 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -134,6 +134,7 @@ GEM has_scope (0.7.2) actionpack (>= 4.1) activesupport (>= 4.1) + hashie (3.5.7) i18n (1.0.1) concurrent-ruby (~> 1.0) io-like (0.3.0) @@ -354,6 +355,7 @@ DEPENDENCIES guard guard-minitest has_scope + hashie jbuilder (~> 2.5) kaminari launchy diff --git a/INSTALL.md b/INSTALL.md index 7c6cf3d..afe5a26 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -45,11 +45,13 @@ To use elliptic curve SSH keys, we need to have `libsodium` and its headers. ## Rails configuration -After cloning this repository, you have to create and edit a few files from example files, for your local development configuration : +After cloning this repository, you have to create and edit a few files from example or defaults files, for your local development configuration : - `config/database.yml` -- `config/chexpire.yml` - `config/secrets.yml` +- `config/chexpire.yml` : set at least the `mailer_default_from` and `host` variables. See other configuration overridable in `config/chexpire.defaults.yml`. + +Theses files will be ignored by git. ## Database diff --git a/README.md b/README.md index 5800ae6..7bd1609 100644 --- a/README.md +++ b/README.md @@ -62,5 +62,5 @@ Finally, you have to write the way the checks will be notified to theirs users. - expires_soon - recurrent_failures -First, add your checks kinds and these notifications definitions in the base class for notifier: `app/services/notifier/base.rb` : in the notify method, for your new check kind, a specific method will be called in each notifier. For example, in the email channel, a specific mailer action is called for each couple (check kin, notification kind). +First, add your checks kinds and these notifications definitions in the base class for notifier: `app/services/notifier/channels/base.rb` : in the notify method, for your new check kind, a specific method will be called in each notifier. For example, in the email channel, a specific mailer action is called for each couple (check kin, notification kind). Then, in each notifier class, implements the details of this method. If you want to ignore a notification for a given channel, simply write the method and do nothing. diff --git a/app/controllers/checks_controller.rb b/app/controllers/checks_controller.rb index d252411..cc12afd 100644 --- a/app/controllers/checks_controller.rb +++ b/app/controllers/checks_controller.rb @@ -6,7 +6,9 @@ class ChecksController < ApplicationController has_scope :kind has_scope :by_domain - has_scope :recurrent_failures, type: :boolean + has_scope :recurrent_failures, type: :boolean do |_controller, scope, _value| + scope.consecutive_failures(Rails.configuration.chexpire.interface.consecutive_failures_as_error) + end def index @checks = apply_scopes(policy_scope(Check)).order(Hash[*current_sort]).page(params[:page]) diff --git a/app/helpers/checks_helper.rb b/app/helpers/checks_helper.rb index f779644..beeea2e 100644 --- a/app/helpers/checks_helper.rb +++ b/app/helpers/checks_helper.rb @@ -29,7 +29,12 @@ module ChecksHelper end end - def check_in_error(check) + def check_in_error?(check) + check.consecutive_failures >= + Rails.configuration.chexpire.interface.consecutive_failures_as_error + end + + def check_error(check) content_tag( :span, Octicons::Octicon.new("alert", class: "ml-1").to_svg.html_safe, diff --git a/app/mailers/notifications_mailer.rb b/app/mailers/notifications_mailer.rb index 31a4677..8f79612 100644 --- a/app/mailers/notifications_mailer.rb +++ b/app/mailers/notifications_mailer.rb @@ -1,34 +1,38 @@ class NotificationsMailer < ApplicationMailer helper :application - before_action do + before_action except: :recurrent_failures do @notification = params.fetch(:notification) @check = @notification.check end - default to: -> { @notification.recipient } - def domain_expires_soon @expire_in_days = Integer(@check.domain_expires_at.to_date - Date.today) - subject = t(".subject", domain: @check.domain, count: @expire_in_days) - mail subject: subject - end - - def domain_recurrent_failures - subject = t(".subject", domain: @check.domain) - mail subject: subject + I18n.with_locale params&.fetch(:locale) { @check.user.locale } do + subject = t(".subject", domain: @check.domain, count: @expire_in_days) + mail subject: subject, to: @notification.recipient + end end def ssl_expires_soon @expire_in_days = Integer(@check.domain_expires_at.to_date - Date.today) - subject = t(".subject", domain: @check.domain, count: @expire_in_days) - mail subject: subject + I18n.with_locale params&.fetch(:locale) { @check.user.locale } do + subject = t(".subject", domain: @check.domain, count: @expire_in_days) + mail subject: subject, to: @notification.recipient + end end - def ssl_recurrent_failures - subject = t(".subject", domain: @check.domain) - mail subject: subject + def recurrent_failures(user, checks) + @checks = checks + + # params generally not set, except for preview mailer + params_locale = (params[:locale] if params.present?) + + I18n.with_locale params_locale || user.locale do + subject = t(".subject", count: checks.count, domain: checks.first.domain) + mail subject: subject, to: user.email + end end end diff --git a/app/models/check.rb b/app/models/check.rb index 296f57f..8e1cb6f 100644 --- a/app/models/check.rb +++ b/app/models/check.rb @@ -2,20 +2,21 @@ # # Table name: checks # -# id :bigint(8) not null, primary key -# active :boolean default(TRUE), not null -# comment :string(255) -# domain :string(255) not null -# domain_created_at :datetime -# domain_expires_at :datetime -# domain_updated_at :datetime -# kind :integer not null -# last_run_at :datetime -# last_success_at :datetime -# vendor :string(255) -# created_at :datetime not null -# updated_at :datetime not null -# user_id :bigint(8) +# id :bigint(8) not null, primary key +# active :boolean default(TRUE), not null +# comment :string(255) +# consecutive_failures :integer default(0), not null +# domain :string(255) not null +# domain_created_at :datetime +# domain_expires_at :datetime +# domain_updated_at :datetime +# kind :integer not null +# last_run_at :datetime +# last_success_at :datetime +# vendor :string(255) +# created_at :datetime not null +# updated_at :datetime not null +# user_id :bigint(8) # # Indexes # @@ -27,8 +28,6 @@ # class Check < ApplicationRecord - ERROR_DELAY_DAYS = 3 - belongs_to :user has_many :logs, class_name: "CheckLog", dependent: :destroy has_many :notifications, validate: true, dependent: :destroy @@ -51,6 +50,7 @@ class Check < ApplicationRecord validates :comment, length: { maximum: 255 } validates :vendor, length: { maximum: 255 } + before_save :reset_consecutive_failures after_update :reset_notifications after_save :enqueue_sync @@ -62,30 +62,25 @@ class Check < ApplicationRecord scope :kind, ->(kind) { where(kind: kind) } scope :by_domain, ->(domain) { where("domain LIKE ?", "%#{domain}%") } - scope :recurrent_failures, -> { - interval = "INTERVAL #{ERROR_DELAY_DAYS} DAY" - where("last_run_at IS NOT NULL AND created_at <= DATE_SUB(NOW(), #{interval})") - .where("last_success_at IS NULL OR last_success_at <= DATE_SUB(last_run_at, #{interval})") + scope :consecutive_failures, ->(consecutive) { + where("consecutive_failures >= ?", consecutive) } def self.default_sort [:domain_expires_at, :asc] end - def in_error? - return false if created_at > ERROR_DELAY_DAYS.days.ago - return false if last_run_at.nil? - return true if last_success_at.nil? - - last_success_at < ERROR_DELAY_DAYS.days.ago - end - def days_from_last_success return unless last_success_at.present? (Date.today - last_success_at.to_date).to_i end + def increment_consecutive_failures! + self.consecutive_failures += 1 + save! + end + private def domain_created_at_past @@ -108,4 +103,11 @@ class Check < ApplicationRecord notifications.each(&:reset!) end + + def reset_consecutive_failures + return unless last_success_at_changed? + return if consecutive_failures_changed? + + self.consecutive_failures = 0 + end end diff --git a/app/services/check_logger.rb b/app/services/check_logger.rb index e04b077..5fe256a 100644 --- a/app/services/check_logger.rb +++ b/app/services/check_logger.rb @@ -1,8 +1,11 @@ class CheckLogger + attr_reader :check attr_reader :check_log def initialize(check) + @check = check @check_log = CheckLog.create!(check: check, status: :pending) + @error_logged = false end def log(event, message) @@ -12,7 +15,13 @@ class CheckLogger when :parsed_response log_parsed_response(message) when :parser_error, :service_error, :standard_error + # avoid multiple logging & wrong incrementation of consecutive failures + # (because a Service exception could be re-raised from a Job) + return if error_logged? + log_error(message) + + @error_logged = true end end @@ -41,7 +50,12 @@ class CheckLogger end def log_error(exception) + check.increment_consecutive_failures! check_log.error = [exception.message, exception.backtrace].join("\n") check_log.failed! end + + def error_logged? + @error_logged + end end diff --git a/app/services/check_processor.rb b/app/services/check_processor.rb index abe087c..9492505 100644 --- a/app/services/check_processor.rb +++ b/app/services/check_processor.rb @@ -28,14 +28,14 @@ module CheckProcessor def resolve_expire_long_term scope .where("DATE(domain_expires_at) >= DATE_ADD(CURDATE(), INTERVAL ? DAY)", - configuration.long_term) + configuration.long_term_interval) .where("DATEDIFF(domain_expires_at, CURDATE()) MOD ? = 0", configuration.long_term_frequency) end def resolve_expire_short_term scope.where("DATE(domain_expires_at) < DATE_ADD(CURDATE(), INTERVAL ? DAY)", - configuration.long_term) + configuration.long_term_interval) end def resolve_unknown_expiry @@ -71,12 +71,6 @@ module CheckProcessor private def default_configuration - config = Rails.configuration.chexpire.fetch(configuration_key, {}) - - OpenStruct.new( - interval: config.fetch("interval") { 0.00 }, - long_term: config.fetch("long_term") { 60 }, - long_term_frequency: config.fetch("long_term_frequency") { 10 }, - ) + Rails.configuration.chexpire.fetch(configuration_key) end end diff --git a/app/services/notifier/channels/base.rb b/app/services/notifier/channels/base.rb index a3e9586..5c879aa 100644 --- a/app/services/notifier/channels/base.rb +++ b/app/services/notifier/channels/base.rb @@ -1,39 +1,33 @@ module Notifier module Channels class Base - def notify(reason, notification) # rubocop:disable Metrics/MethodLength - return unless supports?(reason, notification) + def notify(notification) # rubocop:disable Metrics/MethodLength + return unless supports?(notification) notification.ongoing! - case [notification.check.kind.to_sym, reason] - when [:domain, :expires_soon] + case notification.check.kind.to_sym + when :domain domain_notify_expires_soon(notification) - when [:domain, :recurrent_failures] - domain_notify_recurrent_failures(notification) - when [:ssl, :expires_soon] + when :ssl ssl_notify_expires_soon(notification) - when [:ssl, :recurrent_failures] - ssl_notify_recurrent_failures(notification) else fail ArgumentError, - "Invalid notification reason `#{reason}` for check kind `#{notification.check.kind}`." + "Invalid notification for check kind `#{notification.check.kind}`." end end private # :nocov: - def supports?(_reason, _notification) + def supports?(_notification) fail NotImplementedError, "#{self.class.name} channel did not implemented method #{__callee__}" end %i[ domain_notify_expires_soon - domain_notify_recurrent_failures ssl_notify_expires_soon - ssl_notify_recurrent_failures ].each do |method| define_method(method) do fail NotImplementedError, diff --git a/app/services/notifier/channels/email.rb b/app/services/notifier/channels/email.rb index 9243b7d..9141ee0 100644 --- a/app/services/notifier/channels/email.rb +++ b/app/services/notifier/channels/email.rb @@ -1,29 +1,25 @@ module Notifier module Channels class Email < Base - REASONS = %i[expires_soon recurrent_failures].freeze + # Error notifications - all checks grouped by user + def notify_recurrent_failures(user, checks) + NotificationsMailer.recurrent_failures(user, checks).deliver_now + end protected - def supports?(reason, _notification) - REASONS.include?(reason) + def supports?(_notification) + true end + # Expiration notifications def domain_notify_expires_soon(notification) NotificationsMailer.with(notification: notification).domain_expires_soon.deliver_now end - def domain_notify_recurrent_failures(notification) - NotificationsMailer.with(notification: notification).domain_recurrent_failures.deliver_now - end - def ssl_notify_expires_soon(notification) NotificationsMailer.with(notification: notification).ssl_expires_soon.deliver_now end - - def ssl_notify_recurrent_failures(notification) - NotificationsMailer.with(notification: notification).ssl_recurrent_failures.deliver_now - end end end end diff --git a/app/services/notifier/processor.rb b/app/services/notifier/processor.rb index 2d7fe15..8d3cad3 100644 --- a/app/services/notifier/processor.rb +++ b/app/services/notifier/processor.rb @@ -1,5 +1,5 @@ module Notifier - Configuration = Struct.new(:interval, :failure_days) + Configuration = Struct.new(:interval, :consecutive_failures) class Processor attr_reader :configuration @@ -16,18 +16,19 @@ module Notifier end def process_expires_soon - resolver.resolve_expires_soon.find_each do |notification| - notifier_channel_for(notification).notify(:expires_soon, notification) + resolver.notifications_expiring_soon.find_each do |notification| + notifier_channel_for(notification).notify(notification) sleep configuration.interval end end + # Notify checks in error by email to the check owner adress email. + # A single email contains all checks for a same user. def process_recurrent_failures - resolver.resolve_check_failed.find_each do |notification| - next unless should_notify_for_recurrent_failures?(notification) - - notifier_channel_for(notification).notify(:recurrent_failures, notification) + failed_checks = resolver.checks_recurrent_failures(configuration.consecutive_failures) + failed_checks.group_by(&:user).each_pair do |user, checks| + channels[:email].notify_recurrent_failures(user, checks) sleep configuration.interval end @@ -36,21 +37,11 @@ module Notifier private def default_configuration - config = Rails.configuration.chexpire.fetch("notifier", {}) - - Configuration.new( - config.fetch("interval") { 0.00 }, - config.fetch("failures_days") { 3 }, - ) + Rails.configuration.chexpire.fetch("notifier") end def notifier_channel_for(notification) channels.fetch(notification.channel.to_sym) end - - def should_notify_for_recurrent_failures?(_notification) - true - # TODO: dependent of logs consecutive failures - end end end diff --git a/app/services/notifier/resolver.rb b/app/services/notifier/resolver.rb index a157860..25c3592 100644 --- a/app/services/notifier/resolver.rb +++ b/app/services/notifier/resolver.rb @@ -1,18 +1,18 @@ module Notifier class Resolver - def resolve_expires_soon + def notifications_expiring_soon scope .where("checks.domain_expires_at >= CURDATE()") .where("DATE(checks.domain_expires_at) <= DATE_ADD(CURDATE(), INTERVAL notifications.interval DAY)") end - def resolve_check_failed - # Only gets here the checks having its last run in error - # Logical rules are in plain ruby inside processor - scope - .includes(check: :logs) - .merge(Check.last_run_failed) + def checks_recurrent_failures(min_consecutive) + Check + .active + .consecutive_failures(min_consecutive) + .includes(:user) + .where.not(user: ignore_users) end private diff --git a/app/views/checks/_table.html.erb b/app/views/checks/_table.html.erb index f4020fa..3808d01 100644 --- a/app/views/checks/_table.html.erb +++ b/app/views/checks/_table.html.erb @@ -26,7 +26,7 @@ <%= t(".kind_labels.#{check.kind}") %> - <%= check_in_error(check) if check.in_error? %> + <%= check_error(check) if check_in_error?(check) %> <%= check.domain %> diff --git a/app/views/notifications_mailer/_check_comment_vendor.en.html.erb b/app/views/notifications_mailer/_check_comment_vendor.en.html.erb index 9c96749..8394dd9 100644 --- a/app/views/notifications_mailer/_check_comment_vendor.en.html.erb +++ b/app/views/notifications_mailer/_check_comment_vendor.en.html.erb @@ -1,13 +1,13 @@ -<%- if @check.comment.present? -%> +<%- if check.comment.present? -%>

You wrote the following comment with this domain:

- <%= @check.comment -%> + <%= check.comment -%>

<%- end -%> -<%- if @check.vendor.present? -%> -Vendor: <%= @check.vendor %> +<%- if check.vendor.present? -%> +Vendor: <%= check.vendor %> <% end %> diff --git a/app/views/notifications_mailer/_check_comment_vendor.en.text.erb b/app/views/notifications_mailer/_check_comment_vendor.en.text.erb index 7407cc1..2f62655 100644 --- a/app/views/notifications_mailer/_check_comment_vendor.en.text.erb +++ b/app/views/notifications_mailer/_check_comment_vendor.en.text.erb @@ -1,11 +1,9 @@ -<%- if @check.comment.present? -%> +<%- if check.comment.present? -%> You wrote the following comment with this domain: - <%= @check.comment -%> + <%= check.comment -%> <%- end -%> - - -<%- if @check.vendor.present? -%> -Vendor: <%= @check.vendor %> +<%- if check.vendor.present? -%> +Vendor: <%= check.vendor %> <% end %> diff --git a/app/views/notifications_mailer/_check_comment_vendor.fr.html.erb b/app/views/notifications_mailer/_check_comment_vendor.fr.html.erb index c2d7576..a2772ff 100644 --- a/app/views/notifications_mailer/_check_comment_vendor.fr.html.erb +++ b/app/views/notifications_mailer/_check_comment_vendor.fr.html.erb @@ -1,13 +1,13 @@ -<%- if @check.comment.present? -%> +<%- if check.comment.present? -%>

Vous avez saisi le commentaire suivant pour ce domaine :

- <%= @check.comment -%> + <%= check.comment -%>

<%- end -%> -<%- if @check.vendor.present? -%> -Fournisseur : <%= @check.vendor %> +<%- if check.vendor.present? -%> +Fournisseur : <%= check.vendor %> <% end %> diff --git a/app/views/notifications_mailer/_check_comment_vendor.fr.text.erb b/app/views/notifications_mailer/_check_comment_vendor.fr.text.erb index b52e291..6bddf75 100644 --- a/app/views/notifications_mailer/_check_comment_vendor.fr.text.erb +++ b/app/views/notifications_mailer/_check_comment_vendor.fr.text.erb @@ -1,11 +1,8 @@ -<%- if @check.comment.present? -%> +<%- if check.comment.present? -%> Vous avez saisi le commentaire suivant pour ce domaine : - - <%= @check.comment -%> + <%= check.comment -%> <%- end -%> - - -<%- if @check.vendor.present? -%> -Fournisseur : <%= @check.vendor %> +<%- if check.vendor.present? -%> +Fournisseur : <%= check.vendor %> <% end %> diff --git a/app/views/notifications_mailer/_domain_recurrent_failure.en.html.erb b/app/views/notifications_mailer/_domain_recurrent_failure.en.html.erb new file mode 100644 index 0000000..2b47a94 --- /dev/null +++ b/app/views/notifications_mailer/_domain_recurrent_failure.en.html.erb @@ -0,0 +1,23 @@ +

+ Domain: <%= check.domain %> (<%= check.consecutive_failures %> consecutive errors) + +
+ + <%- if check.domain_expires_at.present? %> + Last known expiry date : <%= format_utc(check.domain_expires_at) %>. +
+ <% end %> + + <%- if check.last_success_at.present? %> + Last successful check occured : <%= format_utc(check.last_success_at) %>. +
+ <% end %> +

+ + +

If you have deleted your domain or have not renewed it, please disable +or delete the check by following this link:
+<%= edit_check_url(check) %> +

+ +<%= render "check_comment_vendor", check: check %> diff --git a/app/views/notifications_mailer/_domain_recurrent_failure.en.text.erb b/app/views/notifications_mailer/_domain_recurrent_failure.en.text.erb new file mode 100644 index 0000000..61ec36c --- /dev/null +++ b/app/views/notifications_mailer/_domain_recurrent_failure.en.text.erb @@ -0,0 +1,15 @@ +Domain: <%= check.domain %> (<%= check.consecutive_failures %> consecutive errors) +<%= "-" * (check.domain.length + "Domain: ".length) %> + +<%- if check.domain_expires_at.present? %> +Last known expiry date : <%= format_utc(check.domain_expires_at) %>. +<% end %> +<%- if check.last_success_at.present? %> +Last successful check occured : <%= format_utc(check.last_success_at) %>. +<% end %> + +If you have deleted your domain or have not renewed it, please disable +or delete the check by following this link: +<%= edit_check_url(check) %> + +<%= render "check_comment_vendor", check: check %> diff --git a/app/views/notifications_mailer/_domain_recurrent_failure.fr.html.erb b/app/views/notifications_mailer/_domain_recurrent_failure.fr.html.erb new file mode 100644 index 0000000..ba96bf3 --- /dev/null +++ b/app/views/notifications_mailer/_domain_recurrent_failure.fr.html.erb @@ -0,0 +1,18 @@ +

+ Domaine: <%= check.domain %> (<%= check.consecutive_failures %> erreurs consécutives) +
+ <%- if check.domain_expires_at.present? %> + Dernière date d'expiration connue : <%= format_utc(check.domain_expires_at) %>. +
+ <% end %> + + <%- if check.last_success_at.present? %> + Dernière vérification réussie : <%= format_utc(check.last_success_at) %>. + <% end %> +

+ +

+Si vous avez supprimé le domaine ou ne l'avez pas renouvellé, merci de désactiver la vérification associée, avec ce lien :
+<%= link_to nil, edit_check_url(check) %> +

+<%= render "check_comment_vendor", check: check %> diff --git a/app/views/notifications_mailer/_domain_recurrent_failure.fr.text.erb b/app/views/notifications_mailer/_domain_recurrent_failure.fr.text.erb new file mode 100644 index 0000000..82d8c67 --- /dev/null +++ b/app/views/notifications_mailer/_domain_recurrent_failure.fr.text.erb @@ -0,0 +1,15 @@ +Domaine: <%= check.domain %> (<%= check.consecutive_failures %> erreurs consécutives) +<%= "-" * (check.domain.length + "Domaine: ".length) %> + +<%- if check.domain_expires_at.present? %> +Dernière date d'expiration connue : <%= format_utc(check.domain_expires_at) %>. +<% end %> +<%- if check.last_success_at.present? %> +Dernière vérification réussie : <%= format_utc(check.last_success_at) %>. +<% end %> + +Si vous avez supprimé le domaine ou ne l'avez pas renouvellé, +merci de désactiver la vérification associée, avec ce lien : +<%= edit_check_url(check) %> + +<%= render "check_comment_vendor", check: check %> diff --git a/app/views/notifications_mailer/_footer_recurrent_failures.en.html.erb b/app/views/notifications_mailer/_footer_recurrent_failures.en.html.erb index beeffb8..b5159d8 100644 --- a/app/views/notifications_mailer/_footer_recurrent_failures.en.html.erb +++ b/app/views/notifications_mailer/_footer_recurrent_failures.en.html.erb @@ -1,11 +1,8 @@
-
-- -

You received this email because of the notification <%= interval %> days before -the last known expiry date.
-You can handle the check by following this link:
-<%= link_to nil, edit_check_url(check) %> +

You can handle all your checks by following this link:
+<%= link_to nil, checks_url %>

The Chexpire Team

diff --git a/app/views/notifications_mailer/_footer_recurrent_failures.en.text.erb b/app/views/notifications_mailer/_footer_recurrent_failures.en.text.erb index b5a42ec..e91b7ae 100644 --- a/app/views/notifications_mailer/_footer_recurrent_failures.en.text.erb +++ b/app/views/notifications_mailer/_footer_recurrent_failures.en.text.erb @@ -1,8 +1,6 @@ -- -You received this email because of the notification <%= interval %> days before -the last known expiry date. -You can handle the check by following this link: -<%= edit_check_url(check) %> +You can handle all your checks by following this link: +<%= checks_url %> The Chexpire Team diff --git a/app/views/notifications_mailer/_footer_recurrent_failures.fr.html.erb b/app/views/notifications_mailer/_footer_recurrent_failures.fr.html.erb index bb35480..0f13c9e 100644 --- a/app/views/notifications_mailer/_footer_recurrent_failures.fr.html.erb +++ b/app/views/notifications_mailer/_footer_recurrent_failures.fr.html.erb @@ -1,10 +1,8 @@
-
-- -

Vous avez reçu ce courriel à <%= pluralize(interval, "jour", "jours") %> avant la dernière date d'expiration connue.
-Vous pouvez gérer les notifications pour cette vérification à ce adresse : -<%= link_to nil, edit_check_url(check) %> +

Vous pouvez gérer l'ensemble de vos vérifications à cette adresse :
+<%= link_to nil, checks_url %>

L'équipe Chexpire

diff --git a/app/views/notifications_mailer/_footer_recurrent_failures.fr.text.erb b/app/views/notifications_mailer/_footer_recurrent_failures.fr.text.erb index a77dd21..60c4ef6 100644 --- a/app/views/notifications_mailer/_footer_recurrent_failures.fr.text.erb +++ b/app/views/notifications_mailer/_footer_recurrent_failures.fr.text.erb @@ -1,8 +1,6 @@ -- -Vous avez reçu ce courriel à <%= pluralize(interval, "jour", "jours") %> -avant la dernière date d'expiration connue. -Vous pouvez gérer les notifications pour cette vérification à ce adresse : -<%= edit_check_url(check) %> +Vous pouvez gérer l'ensemble de vos vérifications à cette adresse : +<%= checks_url %> L'équipe Chexpire diff --git a/app/views/notifications_mailer/_ssl_recurrent_failure.en.html.erb b/app/views/notifications_mailer/_ssl_recurrent_failure.en.html.erb new file mode 100644 index 0000000..1ce2fd3 --- /dev/null +++ b/app/views/notifications_mailer/_ssl_recurrent_failure.en.html.erb @@ -0,0 +1,22 @@ +

+ SSL: <%= check.domain %> (<%= check.consecutive_failures %> erreurs consécutives) +
+ + <%- if check.domain_expires_at.present? %> + Last known expiry date : <%= format_utc(check.domain_expires_at) %>. +
+ <%- end %> + + <%- if check.last_success_at.present? %> + Last successful check : <%= format_utc(check.last_success_at) %>. +
+ <%- end %> +

+ +

+If there is no more SSL endpoint for this domain, please disable +or delete the check by following this link:
+<%= edit_check_url(check) %> +

+ +<%= render "check_comment_vendor", check: check %> diff --git a/app/views/notifications_mailer/_ssl_recurrent_failure.en.text.erb b/app/views/notifications_mailer/_ssl_recurrent_failure.en.text.erb new file mode 100644 index 0000000..52c5179 --- /dev/null +++ b/app/views/notifications_mailer/_ssl_recurrent_failure.en.text.erb @@ -0,0 +1,15 @@ +SSL: <%= check.domain %> (<%= check.consecutive_failures %> erreurs consécutives) +<%= "-" * (check.domain.length + "SSL: ".length) %> + +<%- if check.domain_expires_at.present? %> +Last known expiry date : <%= format_utc(check.domain_expires_at) %>. +<%- end %> +<%- if check.last_success_at.present? %> +Last successful check : <%= format_utc(check.last_success_at) %>. +<%- end %> + +If there is no more SSL endpoint for this domain, please disable +or delete the check by following this link: +<%= edit_check_url(check) %> + +<%= render "check_comment_vendor", check: check %> diff --git a/app/views/notifications_mailer/_ssl_recurrent_failure.fr.html.erb b/app/views/notifications_mailer/_ssl_recurrent_failure.fr.html.erb new file mode 100644 index 0000000..18d1cfc --- /dev/null +++ b/app/views/notifications_mailer/_ssl_recurrent_failure.fr.html.erb @@ -0,0 +1,20 @@ +

+ SSL: <%= check.domain %> (<%= check.consecutive_failures %> erreurs consécutives) +
+ + <%- if check.domain_expires_at.present? %> + Dernière date d'expiration connue : <%= format_utc(check.domain_expires_at) %>. +
+ <% end %> + + <%- if check.last_success_at.present? %> + Dernière vérification réussie : <%= format_utc(check.last_success_at) %>. + <% end %> +

+ +

+ S'il n'y a plus de terminaison SSL pour ce site ou s'il n'existe plus, + merci de désactiver la vérification associée, avec ce lien :
+<%= link_to nil, edit_check_url(check) %> +

+<%= render "check_comment_vendor", check: check %> diff --git a/app/views/notifications_mailer/_ssl_recurrent_failure.fr.text.erb b/app/views/notifications_mailer/_ssl_recurrent_failure.fr.text.erb new file mode 100644 index 0000000..4492ca8 --- /dev/null +++ b/app/views/notifications_mailer/_ssl_recurrent_failure.fr.text.erb @@ -0,0 +1,15 @@ +SSL: <%= check.domain %> (<%= check.consecutive_failures %> erreurs consécutives) +<%= "-" * (check.domain.length + "SSL: ".length) %> + +<%- if check.domain_expires_at.present? %> +Dernière date d'expiration connue : <%= format_utc(check.domain_expires_at) %>. +<% end %> +<%- if check.last_success_at.present? %> +Dernière vérification réussie : <%= format_utc(check.last_success_at) %>. +<% end %> + +S'il n'y a plus de terminaison SSL pour ce site ou s'il n'existe plus, +merci de désactiver la vérification associée, avec ce lien : +<%= edit_check_url(check) %> + +<%= render "check_comment_vendor", check: check %> diff --git a/app/views/notifications_mailer/domain_expires_soon.en.html.erb b/app/views/notifications_mailer/domain_expires_soon.en.html.erb index d3b087f..9fb05a7 100644 --- a/app/views/notifications_mailer/domain_expires_soon.en.html.erb +++ b/app/views/notifications_mailer/domain_expires_soon.en.html.erb @@ -7,6 +7,6 @@


-<%= render "check_comment_vendor" %> +<%= render "check_comment_vendor", check: @check %> <%= render "footer_expires_soon", interval: @notification.interval, check: @check %> diff --git a/app/views/notifications_mailer/domain_expires_soon.en.text.erb b/app/views/notifications_mailer/domain_expires_soon.en.text.erb index c42e60a..6e93342 100644 --- a/app/views/notifications_mailer/domain_expires_soon.en.text.erb +++ b/app/views/notifications_mailer/domain_expires_soon.en.text.erb @@ -3,7 +3,7 @@ Hi, the domain <%= @check.domain %> will expire <%= format_utc(@check.domain_expires_at) %>. -<%= render "check_comment_vendor" %> +<%= render "check_comment_vendor", check: @check %> <%= render "footer_expires_soon", interval: @notification.interval, check: @check %> diff --git a/app/views/notifications_mailer/domain_expires_soon.fr.html.erb b/app/views/notifications_mailer/domain_expires_soon.fr.html.erb index 9b39910..6aa8e1c 100644 --- a/app/views/notifications_mailer/domain_expires_soon.fr.html.erb +++ b/app/views/notifications_mailer/domain_expires_soon.fr.html.erb @@ -7,6 +7,6 @@


-<%= render "check_comment_vendor" %> +<%= render "check_comment_vendor", check: @check %> <%= render "footer_expires_soon", interval: @notification.interval, check: @check %> diff --git a/app/views/notifications_mailer/domain_expires_soon.fr.text.erb b/app/views/notifications_mailer/domain_expires_soon.fr.text.erb index 2caad62..126ac40 100644 --- a/app/views/notifications_mailer/domain_expires_soon.fr.text.erb +++ b/app/views/notifications_mailer/domain_expires_soon.fr.text.erb @@ -3,7 +3,7 @@ Salut, le domaine <%= @check.domain %> va expirer le <%= format_utc(@check.domain_expires_at) %>. -<%= render "check_comment_vendor" %> +<%= render "check_comment_vendor", check: @check %> <%= render "footer_expires_soon", interval: @notification.interval, check: @check %> diff --git a/app/views/notifications_mailer/domain_recurrent_failures.en.html.erb b/app/views/notifications_mailer/domain_recurrent_failures.en.html.erb deleted file mode 100644 index 2146dbc..0000000 --- a/app/views/notifications_mailer/domain_recurrent_failures.en.html.erb +++ /dev/null @@ -1,30 +0,0 @@ -

- Hi, -
-
- - We had recurrent failures while checking the whois database for domain - <%= @check.domain %>. As of today, we can't anymore verify the expiry date. -

- -

- <%- if @check.domain_expires_at.present? %> - Our last known expiry date is <%= format_utc(@check.domain_expires_at) %>. -
- <% end %> - - <%- if @check.last_success_at.present? %> - Our last successful check occured <%= format_utc(@check.last_success_at) %>. - <% end %> -

- -

-If you have deleted the domain or have not renewed it, please disable -or delete the check by following this link:

-<%= link_to nil, edit_check_url(@check) %> -

-
-<%= render "check_comment_vendor" %> - - -<%= render "footer_recurrent_failures", interval: @notification.interval, check: @check %> diff --git a/app/views/notifications_mailer/domain_recurrent_failures.en.text.erb b/app/views/notifications_mailer/domain_recurrent_failures.en.text.erb deleted file mode 100644 index b5ce466..0000000 --- a/app/views/notifications_mailer/domain_recurrent_failures.en.text.erb +++ /dev/null @@ -1,20 +0,0 @@ -Hi, - -We had recurrent failures while checking the whois database for domain -<%= @check.domain %>. As of today, we can't anymore verify the expiry date. - -<%- if @check.domain_expires_at.present? %> -The last known expiry date is <%= format_utc(@check.domain_expires_at) %>. -<% end %> -<%- if @check.last_success_at.present? %> -The last successful check occured <%= format_utc(@check.last_success_at) %>. -<% end %> - -If you have deleted your domain or have not renewed it, please disable -or delete the check by following this link: - -<%= edit_check_url(@check) %> - -<%= render "check_comment_vendor" %> - -<%= render "footer_recurrent_failures", interval: @notification.interval, check: @check %> diff --git a/app/views/notifications_mailer/domain_recurrent_failures.fr.html.erb b/app/views/notifications_mailer/domain_recurrent_failures.fr.html.erb deleted file mode 100644 index 7da5aed..0000000 --- a/app/views/notifications_mailer/domain_recurrent_failures.fr.html.erb +++ /dev/null @@ -1,29 +0,0 @@ -

- Salut, -
-
- - Nous avons rencontré de multiples erreurs pendant l'exécution des vérifications du domaine <%= @check.domain %>. - Nous ne pouvons plus interroger la base Whois pour vérifier la date d'expiration. -

- -

- <%- if @check.domain_expires_at.present? %> - La dernière date d'expiration connue est le <%= format_utc(@check.domain_expires_at) %>. -
- <% end %> - - <%- if @check.last_success_at.present? %> - Notre dernière vérification réussie a eu lieu le <%= format_utc(@check.last_success_at) %>. - <% end %> -

- -

-Si vous avez supprimé le domaine ou ne l'avez pas renouvellé, merci de désactiver la vérification associée, avec ce lien :

-<%= link_to nil, edit_check_url(@check) %> -

-
-<%= render "check_comment_vendor" %> - - -<%= render "footer_recurrent_failures", interval: @notification.interval, check: @check %> diff --git a/app/views/notifications_mailer/domain_recurrent_failures.fr.text.erb b/app/views/notifications_mailer/domain_recurrent_failures.fr.text.erb deleted file mode 100644 index cb8673e..0000000 --- a/app/views/notifications_mailer/domain_recurrent_failures.fr.text.erb +++ /dev/null @@ -1,20 +0,0 @@ -Salut, - -Nous avons rencontré de multiples erreurs pendant l'exécution des vérifications -du domaine <%= @check.domain %>. -Nous ne pouvons plus interroger la base Whois pour vérifier la date d'expiration. - -<%- if @check.domain_expires_at.present? %> -La dernière date d'expiration connue est le <%= format_utc(@check.domain_expires_at) %>. -<% end %> -<%- if @check.last_success_at.present? %> -Notre dernière vérification réussie a eu lieu le <%= format_utc(@check.last_success_at) %>. -<% end %> - -Si vous avez supprimé le domaine ou ne l'avez pas renouvellé, -merci de désactiver la vérification associée, avec ce lien : -<%= edit_check_url(@check) %> - -<%= render "check_comment_vendor" %> - -<%= render "footer_recurrent_failures", interval: @notification.interval, check: @check %> diff --git a/app/views/notifications_mailer/recurrent_failures.en.html.erb b/app/views/notifications_mailer/recurrent_failures.en.html.erb new file mode 100644 index 0000000..fee55f1 --- /dev/null +++ b/app/views/notifications_mailer/recurrent_failures.en.html.erb @@ -0,0 +1,22 @@ +

+ Hi, +
+
+ + <%= t(".header", count: @checks.count) %> +

+ + +<%- @checks.each_with_index do |check, index| %> + <%- if index > 0 -%> +
+
+
+ <%- end -%> + + <%= render "#{check.kind}_recurrent_failure", check: check %> +<%- end -%> + +
+
+<%= render "footer_recurrent_failures" %> diff --git a/app/views/notifications_mailer/recurrent_failures.en.text.erb b/app/views/notifications_mailer/recurrent_failures.en.text.erb new file mode 100644 index 0000000..d58006b --- /dev/null +++ b/app/views/notifications_mailer/recurrent_failures.en.text.erb @@ -0,0 +1,14 @@ +Hi, + +<%= t(".header", count: @checks.count) %> + +<%- @checks.each_with_index do |check, index| %> + <%- if index > 0 -%> + + <%- end -%> + +<%= render "#{check.kind}_recurrent_failure", check: check %> +<%- end -%> + + +<%= render "footer_recurrent_failures" %> diff --git a/app/views/notifications_mailer/recurrent_failures.fr.html.erb b/app/views/notifications_mailer/recurrent_failures.fr.html.erb new file mode 100644 index 0000000..513a848 --- /dev/null +++ b/app/views/notifications_mailer/recurrent_failures.fr.html.erb @@ -0,0 +1,22 @@ +

+ Salut, +
+
+ + <%= t(".header", count: @checks.count) %> +

+ + +<%- @checks.each_with_index do |check, index| %> + <%- if index > 0 -%> +
+
+
+ <%- end -%> + + <%= render "#{check.kind}_recurrent_failure", check: check %> +<%- end -%> + +
+
+<%= render "footer_recurrent_failures" %> diff --git a/app/views/notifications_mailer/recurrent_failures.fr.text.erb b/app/views/notifications_mailer/recurrent_failures.fr.text.erb new file mode 100644 index 0000000..3726ef9 --- /dev/null +++ b/app/views/notifications_mailer/recurrent_failures.fr.text.erb @@ -0,0 +1,14 @@ +Salut, + +<%= t(".header", count: @checks.count) %> + +<%- @checks.each_with_index do |check, index| %> + <%- if index > 0 -%> + + <%- end -%> + +<%= render "#{check.kind}_recurrent_failure", check: check %> +<%- end -%> + + +<%= render "footer_recurrent_failures" %> diff --git a/app/views/notifications_mailer/ssl_expires_soon.en.html.erb b/app/views/notifications_mailer/ssl_expires_soon.en.html.erb index 401df10..f0a5515 100644 --- a/app/views/notifications_mailer/ssl_expires_soon.en.html.erb +++ b/app/views/notifications_mailer/ssl_expires_soon.en.html.erb @@ -7,6 +7,6 @@


-<%= render "check_comment_vendor" %> +<%= render "check_comment_vendor", check: @check %> <%= render "footer_expires_soon", interval: @notification.interval, check: @check %> diff --git a/app/views/notifications_mailer/ssl_expires_soon.en.text.erb b/app/views/notifications_mailer/ssl_expires_soon.en.text.erb index a1d1c56..73e13dd 100644 --- a/app/views/notifications_mailer/ssl_expires_soon.en.text.erb +++ b/app/views/notifications_mailer/ssl_expires_soon.en.text.erb @@ -3,7 +3,7 @@ Hi, the SSL certificate for <%= @check.domain %> will expire <%= format_utc(@check.domain_expires_at) %>. -<%= render "check_comment_vendor" %> +<%= render "check_comment_vendor", check: @check %> <%= render "footer_expires_soon", interval: @notification.interval, check: @check %> diff --git a/app/views/notifications_mailer/ssl_expires_soon.fr.html.erb b/app/views/notifications_mailer/ssl_expires_soon.fr.html.erb index dfc1c3f..6869687 100644 --- a/app/views/notifications_mailer/ssl_expires_soon.fr.html.erb +++ b/app/views/notifications_mailer/ssl_expires_soon.fr.html.erb @@ -7,6 +7,6 @@


-<%= render "check_comment_vendor" %> +<%= render "check_comment_vendor", check: @check %> <%= render "footer_expires_soon", interval: @notification.interval, check: @check %> diff --git a/app/views/notifications_mailer/ssl_expires_soon.fr.text.erb b/app/views/notifications_mailer/ssl_expires_soon.fr.text.erb index 0664fb5..9f6999c 100644 --- a/app/views/notifications_mailer/ssl_expires_soon.fr.text.erb +++ b/app/views/notifications_mailer/ssl_expires_soon.fr.text.erb @@ -3,7 +3,7 @@ Salut, le certificat SSL pour <%= @check.domain %> va expirer le <%= format_utc(@check.domain_expires_at) %>. -<%= render "check_comment_vendor" %> +<%= render "check_comment_vendor", check: @check %> <%= render "footer_expires_soon", interval: @notification.interval, check: @check %> diff --git a/app/views/notifications_mailer/ssl_recurrent_failures.en.html.erb b/app/views/notifications_mailer/ssl_recurrent_failures.en.html.erb deleted file mode 100644 index 602c32d..0000000 --- a/app/views/notifications_mailer/ssl_recurrent_failures.en.html.erb +++ /dev/null @@ -1,31 +0,0 @@ -

- Hi, -
-
- - We had recurrent failures while checking the SSL certificate for - <%= @check.domain %>. As of today, we can no longer verify the certificate - expiry date. -

- -

- <%- if @check.domain_expires_at.present? %> - Our last known expiry date is <%= format_utc(@check.domain_expires_at) %>. -
- <%- end %> - - <%- if @check.last_success_at.present? %> - Our last successful check occured <%= format_utc(@check.last_success_at) %>. - <%- end %> -

- -

- If there is no more SSL endpoint for this domain, please disable - or delete the check by following this link:

- <%= link_to nil, edit_check_url(@check) %> -

-
-<%= render "check_comment_vendor" %> - - -<%= render "footer_recurrent_failures", interval: @notification.interval, check: @check %> diff --git a/app/views/notifications_mailer/ssl_recurrent_failures.en.text.erb b/app/views/notifications_mailer/ssl_recurrent_failures.en.text.erb deleted file mode 100644 index 2bb6dd3..0000000 --- a/app/views/notifications_mailer/ssl_recurrent_failures.en.text.erb +++ /dev/null @@ -1,22 +0,0 @@ -Hi, - -We had recurrent failures while checking the SSL certificate for -<%= @check.domain %>. As of today, we can no longer verify the certificate -expiry date. - -<%- if @check.domain_expires_at.present? %> -The last known expiry date is <%= format_utc(@check.domain_expires_at) %>. -<%- end %> - -<%- if @check.last_success_at.present? %> -The last successful check occured <%= format_utc(@check.last_success_at) %>. -<%- end %> - -If there is no more SSL endpoint for this domain, please disable -or delete the check by following this link: - -<%= edit_check_url(@check) %> - -<%= render "check_comment_vendor" %> - -<%= render "footer_recurrent_failures", interval: @notification.interval, check: @check %> diff --git a/app/views/notifications_mailer/ssl_recurrent_failures.fr.html.erb b/app/views/notifications_mailer/ssl_recurrent_failures.fr.html.erb deleted file mode 100644 index ea05abc..0000000 --- a/app/views/notifications_mailer/ssl_recurrent_failures.fr.html.erb +++ /dev/null @@ -1,35 +0,0 @@ -

- Salut, -
-
- - Nous avons rencontré de multiples erreurs - pendant l'exécution des vérifications du certificat SSL - du site <%= @check.domain %>. - Nous ne pouvons plus vérifier la date d'expiration du certificat - en nous connectant au site. -

- -

- <%- if @check.domain_expires_at.present? %> - La dernière date d'expiration connue est le <%= format_utc(@check.domain_expires_at) %>. -
- <% end %> - - <%- if @check.last_success_at.present? %> - Notre dernière vérification réussie a eu lieu le <%= format_utc(@check.last_success_at) %>. - <% end %> -

- -

- S'il n'y a plus de terminaison SSL pour ce site ou s'il n'existe plus, - merci de désactiver la vérification associée, avec ce lien : -
-
- <%= link_to nil, edit_check_url(@check) %> -

-
-<%= render "check_comment_vendor" %> - - -<%= render "footer_recurrent_failures", interval: @notification.interval, check: @check %> diff --git a/app/views/notifications_mailer/ssl_recurrent_failures.fr.text.erb b/app/views/notifications_mailer/ssl_recurrent_failures.fr.text.erb deleted file mode 100644 index fe15787..0000000 --- a/app/views/notifications_mailer/ssl_recurrent_failures.fr.text.erb +++ /dev/null @@ -1,22 +0,0 @@ -Salut, - -Nous avons rencontré de multiples erreurs pendant l'exécution des vérifications -du certificat SSL pour le site <%= @check.domain %>. -Nous ne pouvons plus vérifier la date d'expiration du certificat -en nous connectant au site. - -<%- if @check.domain_expires_at.present? %> -La dernière date d'expiration connue est le <%= format_utc(@check.domain_expires_at) %>. -<% end %> - -<%- if @check.last_success_at.present? %> -Notre dernière vérification réussie a eu lieu le <%= format_utc(@check.last_success_at) %>. -<% end %> - -S'il n'y a plus de terminaison SSL pour ce site ou s'il n'existe plus, -merci de désactiver la vérification associée, avec ce lien : -<%= edit_check_url(@check) %> - -<%= render "check_comment_vendor" %> - -<%= render "footer_recurrent_failures", interval: @notification.interval, check: @check %> diff --git a/config/application.rb b/config/application.rb index 5adecf8..9f5c3df 100644 --- a/config/application.rb +++ b/config/application.rb @@ -32,6 +32,12 @@ module Chexpire config.time_zone = "Europe/Paris" - config.chexpire = config_for(:chexpire) + unless Rails.root.join("config", "chexpire.yml").readable? + fail "Missing Chexpire configuration file. + You have to create the config/chexpire.yml file and set at least the required values. + Look at config/chexpire.defaults.yml and INSTALL.md for more information" + end + + config.chexpire = Hashie::Mash.new(config_for(:"chexpire.defaults").deep_merge(config_for(:chexpire))) end end diff --git a/config/chexpire.defaults.yml b/config/chexpire.defaults.yml new file mode 100644 index 0000000..3080d0f --- /dev/null +++ b/config/chexpire.defaults.yml @@ -0,0 +1,53 @@ +# DO NOT EDIT THIS FILE +# +# If you want override a value for any environment, +# create a `config/chexpire.yml` file, +# write your overrided keys under your environment namespace. +# +# Some keys are required to be overidden for your environment. +# +# Example: +# +# production: +# mailer_default_from: "contact@yourdomain.org" +# host: mychexpire.instance.org + +default: &default + mailer_default_from: "from@example.org" # REQUIRED: Email will be sent with this address as From header + host: chexpire.local # REQUIRED: Host of the website. + + interface: + consecutive_failures_as_error: 2 # number of consecutive failures before display a check as "in error" (value for interface only) + notifier: + interval: 0.00 # pause in second between each notification sent + consecutive_failures: 4 # number of consecutive failures before sending a notification for recurrent failures + checks_domain: + interval: 0.5 # pause in second between each whois call + long_term_interval: 300 # when last known expiry date exceeds this interval in days, whois verification won't happen every day + long_term_frequency: 4 # when last known expiry exceeds $long_term, perform whois verification each $long_term_frequency days instead of every day + checks_ssl: + check_http_path: # defaults to check_http in $PATH + check_http_args: # array of arguments appended to defaults arguments (-C 0 -H $HOSTNAME). + +development: + <<: *default + host: "chexpire.local" + +production: + <<: *default + action_mailer_config: + delivery_method: :sendmail + +staging: + <<: *default + action_mailer_config: + delivery_method: :sendmail + +test: + <<: *default + mailer_default_from: "testcontact@example.org" + host: localhost + checks_dummy: + interval: 0.0 + long_term_interval: 60 + long_term_frequency: 10 diff --git a/config/chexpire.example.yml b/config/chexpire.example.yml deleted file mode 100644 index 324a5d7..0000000 --- a/config/chexpire.example.yml +++ /dev/null @@ -1,27 +0,0 @@ -default: &default - mailer_default_from: "from@example.org" - notifier: - interval: 0.00 - failure_days: 3 - checks_domain: - interval: 0.5 - long_term: 60 - long_term_frequency: 10 - checks_ssl: - check_http_path: # default to check_http in $PATH) - check_http_args: # array of arguments appended to defaults: -C 0 -H $HOSTNAME. - -development: - <<: *default - host: "chexpire.local" - -production: - action_mailer_config: - delivery_method: :sendmail - -staging: - action_mailer_config: - delivery_method: :sendmail - -# test configuration included in file used by CI services -<%= IO.read Rails.root.join("config", "chexpire.test.yml") %> diff --git a/config/chexpire.test.yml b/config/chexpire.test.yml deleted file mode 100644 index 6af09a8..0000000 --- a/config/chexpire.test.yml +++ /dev/null @@ -1,13 +0,0 @@ -test: - mailer_default_from: "contact@chexpire.org" - host: "localhost" - notifier: - interval: 0.00 - failure_days: 3 - checks_domain: - interval: 0.00 - long_term: 60 - long_term_frequency: 10 - checks_ssl: - check_http_path: - check_http_args: diff --git a/config/locales/en.yml b/config/locales/en.yml index 554bb3f..7fb3d01 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -40,8 +40,13 @@ en: one: "Domain %{domain} expires TOMORROW!" other: "Domain %{domain} expires in %{count} days" - domain_recurrent_failures: - subject: "Recurrent failures in %{domain} domain expiry check" + recurrent_failures: + subject: + one: "Recurrent failures for %{domain} expiry check" + other: "%{count} checks in error" + header: + one: "We had recurrent failures during excution of the following check:" + other: "We had recurrent failures during excution of the %{count} following checks:" ssl_expires_soon: subject: diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 52241a1..6be381e 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -75,8 +75,13 @@ fr: one: "Le domaine %{domain} expire DEMAIN !" other: "Le domaine %{domain} expire dans %{count} jours" - domain_recurrent_failures: - subject: "Erreurs dans la vérification d'expiration du domaine %{domain}" + recurrent_failures: + subject: + one: "Erreurs de vérification d'expiration pour %{domain}" + other: "%{count} vérifications en erreur" + header: + one: "Nous avons rencontré des erreurs pendant l'exécution d'une de vos vérifications :" + other: "Nous avons rencontré des erreurs pendant l'exécution des %{count} vérifications suivantes :" ssl_expires_soon: subject: @@ -84,10 +89,6 @@ fr: one: "Le certificat SSL pour %{domain} expire DEMAIN !" other: "Le certificat SSL pour %{domain} expire dans %{count} jours" - ssl_recurrent_failures: - subject: "Erreurs dans la vérification d'expiration du certificat SSL %{domain}" - - shared: locales: en: Anglais diff --git a/db/migrate/20180801072038_add_consecutive_failures_to_checks.rb b/db/migrate/20180801072038_add_consecutive_failures_to_checks.rb new file mode 100644 index 0000000..dbf038b --- /dev/null +++ b/db/migrate/20180801072038_add_consecutive_failures_to_checks.rb @@ -0,0 +1,5 @@ +class AddConsecutiveFailuresToChecks < ActiveRecord::Migration[5.2] + def change + add_column :checks, :consecutive_failures, :integer, default: 0, null: false + end +end diff --git a/db/schema.rb b/db/schema.rb index eda5147..024d864 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2018_06_13_055303) do +ActiveRecord::Schema.define(version: 2018_08_01_072038) do create_table "check_logs", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| t.bigint "check_id" @@ -38,6 +38,7 @@ ActiveRecord::Schema.define(version: 2018_06_13_055303) do t.boolean "active", default: true, null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.integer "consecutive_failures", default: 0, null: false t.index ["user_id"], name: "index_checks_on_user_id" end diff --git a/db/seeds.rb b/db/seeds.rb index 996d657..1f353fb 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -43,6 +43,7 @@ check_chexpire_org_error = Check.create!( vendor: "Some random registrar", last_run_at: 20.minutes.ago, created_at: 3.weeks.ago, + consecutive_failures: 4, ) ssl_check_chexpire_org = Check.create!( @@ -67,6 +68,7 @@ ssl_check_chexpire_org_error = Check.create!( vendor: "Some random registrar", last_run_at: 20.minutes.ago, last_success_at: 4.days.ago, + consecutive_failures: 8, ) diff --git a/test/factories/checks.rb b/test/factories/checks.rb index f940eb2..a0cf919 100644 --- a/test/factories/checks.rb +++ b/test/factories/checks.rb @@ -2,20 +2,21 @@ # # Table name: checks # -# id :bigint(8) not null, primary key -# active :boolean default(TRUE), not null -# comment :string(255) -# domain :string(255) not null -# domain_created_at :datetime -# domain_expires_at :datetime -# domain_updated_at :datetime -# kind :integer not null -# last_run_at :datetime -# last_success_at :datetime -# vendor :string(255) -# created_at :datetime not null -# updated_at :datetime not null -# user_id :bigint(8) +# id :bigint(8) not null, primary key +# active :boolean default(TRUE), not null +# comment :string(255) +# consecutive_failures :integer default(0), not null +# domain :string(255) not null +# domain_created_at :datetime +# domain_expires_at :datetime +# domain_updated_at :datetime +# kind :integer not null +# last_run_at :datetime +# last_success_at :datetime +# vendor :string(255) +# created_at :datetime not null +# updated_at :datetime not null +# user_id :bigint(8) # # Indexes # @@ -39,6 +40,7 @@ FactoryBot.define do comment nil last_run_at nil last_success_at nil + consecutive_failures 0 trait :domain do kind :domain @@ -63,6 +65,7 @@ FactoryBot.define do end trait :last_runs_failed do + consecutive_failures 5 last_run_at 3.days.ago - 90.minutes last_success_at 7.days.ago - 2.hours end diff --git a/test/factories/users.rb b/test/factories/users.rb index 4566543..1f8789b 100644 --- a/test/factories/users.rb +++ b/test/factories/users.rb @@ -40,5 +40,9 @@ FactoryBot.define do notifications_enabled true locale "en" tos_accepted true + + trait :fr do + locale "fr" + end end end diff --git a/test/jobs/ssl_sync_job_test.rb b/test/jobs/ssl_sync_job_test.rb index 30b66a4..44e76ed 100644 --- a/test/jobs/ssl_sync_job_test.rb +++ b/test/jobs/ssl_sync_job_test.rb @@ -22,7 +22,6 @@ class SSLSyncJobTest < ActiveJob::TestCase test "ignore invalid response" do domain = "domain.fr" check = create(:check, :nil_dates, domain: domain) - original_updated_at = check.updated_at mock_system_command("check_http", expected_command_arg(domain), stdout: "not a response") do SSLSyncJob.perform_now(check.id) @@ -32,8 +31,8 @@ class SSLSyncJobTest < ActiveJob::TestCase assert_just_now check.last_run_at assert_nil check.last_success_at - assert_equal original_updated_at, check.updated_at assert check.active? + assert_equal 1, check.consecutive_failures end test "should ignore not found (removed) checks" do @@ -51,9 +50,25 @@ class SSLSyncJobTest < ActiveJob::TestCase end end + check.reload + assert_equal 1, check.logs.count assert_match(/undefined method \W+valid\?/, check.logs.last.error) assert check.logs.last.failed? + assert_equal 1, check.consecutive_failures + end + + test "should reset consecutive failures with a valid response" do + domain = "ssl0.domain.org" + check = create(:check, :nil_dates, domain: domain, consecutive_failures: 1) + + mock_system_command("check_http", expected_command_arg(domain), stdout: ssl_response(domain)) do + SSLSyncJob.perform_now(check.id) + end + + check.reload + + assert_equal 0, check.consecutive_failures end private diff --git a/test/jobs/whois_sync_job_test.rb b/test/jobs/whois_sync_job_test.rb index e96755d..401eba0 100644 --- a/test/jobs/whois_sync_job_test.rb +++ b/test/jobs/whois_sync_job_test.rb @@ -33,6 +33,7 @@ class WhoisSyncJobTest < ActiveJob::TestCase assert_nil check.last_success_at assert_equal original_updated_at, check.updated_at assert check.active? + assert_equal 1, check.consecutive_failures end test "should ignore not found (removed) checks" do @@ -50,9 +51,12 @@ class WhoisSyncJobTest < ActiveJob::TestCase end end + check.reload + assert_equal 1, check.logs.count assert_match(/undefined method \W+valid\?/, check.logs.last.error) assert check.logs.last.failed? + assert_equal 1, check.consecutive_failures end test "disable check when whois responds domain not found" do @@ -68,6 +72,7 @@ class WhoisSyncJobTest < ActiveJob::TestCase refute check.active? assert_just_now check.last_run_at assert_nil check.last_success_at + assert_equal 1, check.consecutive_failures end test "default logger is CheckLogger" do @@ -80,6 +85,19 @@ class WhoisSyncJobTest < ActiveJob::TestCase assert_equal 1, check.logs.count end + test "should reset consecutive failures with a valid response" do + domain = "domain.fr" + check = create(:check, :nil_dates, domain: domain, consecutive_failures: 1) + + mock_system_command("whois", domain, stdout: whois_response(domain)) do + WhoisSyncJob.perform_now(check.id) + end + + check.reload + + assert_equal 0, check.consecutive_failures + end + private def whois_response(domain) diff --git a/test/mailers/notifications_mailer_test.rb b/test/mailers/notifications_mailer_test.rb index c261131..6c3f7c4 100644 --- a/test/mailers/notifications_mailer_test.rb +++ b/test/mailers/notifications_mailer_test.rb @@ -31,32 +31,32 @@ class NotificationsMailerTest < ActionMailer::TestCase # rubocop:disable Metrics end test "domain_expires_soon FR" do - check = create(:check, domain_expires_at: Time.new(2018, 6, 10, 12, 0, 5, "+02:00")) + check = create(:check, + domain_expires_at: Time.new(2018, 6, 10, 12, 0, 5, "+02:00"), + user: build(:user, :fr)) notification = build(:notification, interval: 10, check: check, recipient: "colin@example.org") - I18n.with_locale :fr do - Date.stub :today, Date.new(2018, 6, 2) do - mail = NotificationsMailer.with(notification: notification).domain_expires_soon + Date.stub :today, Date.new(2018, 6, 2) do + mail = NotificationsMailer.with(notification: notification).domain_expires_soon - assert_emails 1 do - mail.deliver_now - end + assert_emails 1 do + mail.deliver_now + end - assert_match "domain.fr", mail.subject - assert_match "dans 8 jours", mail.subject - assert_equal ["colin@example.org"], mail.to - assert_equal [Rails.configuration.chexpire.fetch("mailer_default_from")], mail.from + assert_match "domain.fr", mail.subject + assert_match "dans 8 jours", mail.subject + assert_equal ["colin@example.org"], mail.to + assert_equal [Rails.configuration.chexpire.fetch("mailer_default_from")], mail.from - parts = [mail.text_part.decode_body, mail.html_part.decode_body] + parts = [mail.text_part.decode_body, mail.html_part.decode_body] - parts.each do |part| - assert_match "domain.fr", part - assert_match "dim 10 juin 2018 10:00:05 +0000", part - assert_match "10 jours", part - assert_match "/checks/#{check.id}/edit", part - assert_no_match "commentaire", part - assert_no_match "fournisseur", part - end + parts.each do |part| + assert_match "domain.fr", part + assert_match "dim 10 juin 2018 10:00:05 +0000", part + assert_match "10 jours", part + assert_match "/checks/#{check.id}/edit", part + assert_no_match "commentaire", part + assert_no_match "fournisseur", part end end end @@ -82,36 +82,34 @@ class NotificationsMailerTest < ActionMailer::TestCase # rubocop:disable Metrics check = create(:check, domain_expires_at: 1.week.from_now, comment: "My comment", - vendor: "The vendor") + vendor: "The vendor", + user: build(:user, :fr)) notification = build(:notification, check: check) - I18n.with_locale :fr do - mail = NotificationsMailer.with(notification: notification).domain_expires_soon + mail = NotificationsMailer.with(notification: notification).domain_expires_soon - parts = [mail.text_part.decode_body, mail.html_part.decode_body] + parts = [mail.text_part.decode_body, mail.html_part.decode_body] - parts.each do |part| - assert_match "commentaire", part - assert_match "Fournisseur", part - end + parts.each do |part| + assert_match "commentaire", part + assert_match "Fournisseur", part end end - test "domain_recurrent_failures" do + test "recurrent_failures" do last_success_at = Time.new(2018, 5, 30, 6, 10, 0, "+00:00") domain_expires_at = Time.new(2018, 10, 10, 7, 20, 0, "+04:00") - check = build(:check, :last_runs_failed, - domain: "invalid-domain.fr", - last_success_at: last_success_at, - domain_expires_at: domain_expires_at, - comment: "My comment") - notification = create(:notification, check: check) + check = create(:check, :last_runs_failed, + domain: "invalid-domain.fr", + last_success_at: last_success_at, + domain_expires_at: domain_expires_at, + comment: "My comment") - mail = NotificationsMailer.with(notification: notification).domain_recurrent_failures + mail = NotificationsMailer.recurrent_failures(check.user, [check]) assert_match "failures", mail.subject assert_match "invalid-domain.fr", mail.subject - assert_equal ["recipient@domain.fr"], mail.to + assert_match(/user-\d+@chexpire.org/, mail.to.first) assert_equal [Rails.configuration.chexpire.fetch("mailer_default_from")], mail.from parts = [mail.text_part.decode_body, mail.html_part.decode_body] @@ -119,41 +117,39 @@ class NotificationsMailerTest < ActionMailer::TestCase # rubocop:disable Metrics parts.each do |part| assert_match "invalid-domain.fr", part assert_match "recurrent failures", part - assert_match(/success[a-z ]+ Wed, 30 May 2018 06:10:00 \+0000/, part) - assert_match(/expiry[a-z ]+ Wed, 10 Oct 2018 03:20:00 \+0000/, part) + assert_match(/success[a-z: ]+ Wed, 30 May 2018 06:10:00 \+0000/, part) + assert_match(/expiry[a-z: ]+ Wed, 10 Oct 2018 03:20:00 \+0000/, part) assert_match "My comment", part assert_match "/checks/#{check.id}/edit", part end end - test "domain_recurrent_failures - FR" do + test "recurrent_failures - FR" do last_success_at = Time.new(2018, 5, 30, 6, 10, 0, "+00:00") domain_expires_at = Time.new(2018, 10, 10, 7, 20, 0, "+04:00") - check = build(:check, :last_runs_failed, - domain: "invalid-domain.fr", - last_success_at: last_success_at, - domain_expires_at: domain_expires_at, - comment: "My comment") - notification = create(:notification, check: check) + check = create(:check, :last_runs_failed, + domain: "invalid-domain.fr", + last_success_at: last_success_at, + domain_expires_at: domain_expires_at, + comment: "My comment", + user: build(:user, :fr)) - I18n.with_locale :fr do - mail = NotificationsMailer.with(notification: notification).domain_recurrent_failures - assert_match "Erreurs", mail.subject - assert_match "invalid-domain.fr", mail.subject + mail = NotificationsMailer.recurrent_failures(check.user, [check]) + assert_match "Erreurs", mail.subject + assert_match "invalid-domain.fr", mail.subject - assert_equal ["recipient@domain.fr"], mail.to - assert_equal [Rails.configuration.chexpire.fetch("mailer_default_from")], mail.from + assert_match(/user-\d+@chexpire.org/, mail.to.first) + assert_equal [Rails.configuration.chexpire.fetch("mailer_default_from")], mail.from - parts = [mail.text_part.decode_body, mail.html_part.decode_body] + parts = [mail.text_part.decode_body, mail.html_part.decode_body] - parts.each do |part| - assert_match "invalid-domain.fr", part - assert_match "erreurs", part - assert_match(/réussie[a-z ]+ mer 30 mai 2018 06:10:00 \+0000/, part) - assert_match(/expiration[a-z ]+ mer 10 oct. 2018 03:20:00 \+0000/, part) - assert_match "commentaire", part - assert_match "/checks/#{check.id}/edit", part - end + parts.each do |part| + assert_match "invalid-domain.fr", part + assert_match "erreurs", part + assert_match(/réussie[a-z: ]+ mer 30 mai 2018 06:10:00 \+0000/, part) + assert_match(/expiration[a-z: ]+ mer 10 oct. 2018 03:20:00 \+0000/, part) + assert_match "commentaire", part + assert_match "/checks/#{check.id}/edit", part end end @@ -188,95 +184,33 @@ class NotificationsMailerTest < ActionMailer::TestCase # rubocop:disable Metrics end test "ssl_expires_soon - FR" do - check = create(:check, :ssl, domain_expires_at: Time.new(2018, 6, 10, 12, 0, 5, "+02:00")) + check = create(:check, :ssl, + domain_expires_at: Time.new(2018, 6, 10, 12, 0, 5, "+02:00"), + user: build(:user, :fr)) notification = build(:notification, interval: 10, check: check, recipient: "colin@example.org") - I18n.with_locale :fr do - Date.stub :today, Date.new(2018, 6, 2) do - mail = NotificationsMailer.with(notification: notification).ssl_expires_soon + Date.stub :today, Date.new(2018, 6, 2) do + mail = NotificationsMailer.with(notification: notification).ssl_expires_soon - assert_emails 1 do - mail.deliver_now - end - - assert_match "domain.fr", mail.subject - assert_match "SSL", mail.subject - assert_match "dans 8 jours", mail.subject - assert_equal ["colin@example.org"], mail.to - assert_equal [Rails.configuration.chexpire.fetch("mailer_default_from")], mail.from - - parts = [mail.text_part.decode_body, mail.html_part.decode_body] - - parts.each do |part| - assert_match "domain.fr", part - assert_match "dim 10 juin 2018 10:00:05 +0000", part - assert_match "10 jours", part - assert_match "/checks/#{check.id}/edit", part - assert_no_match "commentaire", part - assert_no_match "fournisseur", part - end + assert_emails 1 do + mail.deliver_now end - end - end - test "ssl_recurrent_failures" do - last_success_at = Time.new(2018, 5, 30, 6, 10, 0, "+00:00") - domain_expires_at = Time.new(2018, 10, 10, 7, 20, 0, "+04:00") - check = build(:check, :ssl, :last_runs_failed, - domain: "invalid-domain.fr", - last_success_at: last_success_at, - domain_expires_at: domain_expires_at, - comment: "My comment") - notification = create(:notification, check: check) - - mail = NotificationsMailer.with(notification: notification).ssl_recurrent_failures - assert_match "failures", mail.subject - assert_match "invalid-domain.fr", mail.subject - assert_match "SSL", mail.subject - - assert_equal ["recipient@domain.fr"], mail.to - assert_equal [Rails.configuration.chexpire.fetch("mailer_default_from")], mail.from - - parts = [mail.text_part.decode_body, mail.html_part.decode_body] - - parts.each do |part| - assert_match "invalid-domain.fr", part - assert_match "recurrent failures", part - assert_match(/success[a-z ]+ Wed, 30 May 2018 06:10:00 \+0000/, part) - assert_match(/expiry[a-z ]+ Wed, 10 Oct 2018 03:20:00 \+0000/, part) - assert_match "My comment", part - assert_match "/checks/#{check.id}/edit", part - end - end - - test "ssl_recurrent_failures - FR" do - last_success_at = Time.new(2018, 5, 30, 6, 10, 0, "+00:00") - domain_expires_at = Time.new(2018, 10, 10, 7, 20, 0, "+04:00") - check = build(:check, :ssl, :last_runs_failed, - domain: "invalid-domain.fr", - last_success_at: last_success_at, - domain_expires_at: domain_expires_at, - comment: "My comment") - notification = create(:notification, check: check) - - I18n.with_locale :fr do - mail = NotificationsMailer.with(notification: notification).ssl_recurrent_failures - assert_match "Erreurs", mail.subject - assert_match "invalid-domain.fr", mail.subject + assert_match "domain.fr", mail.subject assert_match "SSL", mail.subject - - assert_equal ["recipient@domain.fr"], mail.to + assert_match "dans 8 jours", mail.subject + assert_equal ["colin@example.org"], mail.to assert_equal [Rails.configuration.chexpire.fetch("mailer_default_from")], mail.from parts = [mail.text_part.decode_body, mail.html_part.decode_body] parts.each do |part| - assert_match "invalid-domain.fr", part - assert_match "erreurs", part - assert_match(/réussie[a-z ]+ mer 30 mai 2018 06:10:00 \+0000/, part) - assert_match(/expiration[a-z ]+ mer 10 oct. 2018 03:20:00 \+0000/, part) - assert_match "commentaire", part + assert_match "domain.fr", part + assert_match "dim 10 juin 2018 10:00:05 +0000", part + assert_match "10 jours", part assert_match "/checks/#{check.id}/edit", part + assert_no_match "commentaire", part + assert_no_match "fournisseur", part end end end diff --git a/test/mailers/previews/notifications_mailer_preview.rb b/test/mailers/previews/notifications_mailer_preview.rb index 01f5085..5371b16 100644 --- a/test/mailers/previews/notifications_mailer_preview.rb +++ b/test/mailers/previews/notifications_mailer_preview.rb @@ -6,21 +6,16 @@ class NotificationsMailerPreview < ActionMailer::Preview NotificationsMailer.with(notification: check.notifications.first).domain_expires_soon end - # Preview this email at http://localhost:3000/rails/mailers/notifications_mailer/domain_recurrent_failures - def domain_recurrent_failures - check = Check.domain.where("last_run_at != last_success_at").first - NotificationsMailer.with(notification: check.notifications.first).domain_recurrent_failures - end - # Preview this email at http://localhost:3000/rails/mailers/notifications_mailer/ssl_expires_soon def ssl_expires_soon check = Check.ssl.first NotificationsMailer.with(notification: check.notifications.first).ssl_expires_soon end - # Preview this email at http://localhost:3000/rails/mailers/notifications_mailer/ssl_recurrent_failures - def ssl_recurrent_failures - check = Check.ssl.where("last_run_at != last_success_at").first - NotificationsMailer.with(notification: check.notifications.first).ssl_recurrent_failures + # Preview this email at http://localhost:3000/rails/mailers/notifications_mailer/recurrent_failures + def recurrent_failures + user = User.first + checks = Check.consecutive_failures(2).where(user: user) + NotificationsMailer.recurrent_failures(user, checks) end end diff --git a/test/models/check_test.rb b/test/models/check_test.rb index 9606150..be81d13 100644 --- a/test/models/check_test.rb +++ b/test/models/check_test.rb @@ -2,20 +2,21 @@ # # Table name: checks # -# id :bigint(8) not null, primary key -# active :boolean default(TRUE), not null -# comment :string(255) -# domain :string(255) not null -# domain_created_at :datetime -# domain_expires_at :datetime -# domain_updated_at :datetime -# kind :integer not null -# last_run_at :datetime -# last_success_at :datetime -# vendor :string(255) -# created_at :datetime not null -# updated_at :datetime not null -# user_id :bigint(8) +# id :bigint(8) not null, primary key +# active :boolean default(TRUE), not null +# comment :string(255) +# consecutive_failures :integer default(0), not null +# domain :string(255) not null +# domain_created_at :datetime +# domain_expires_at :datetime +# domain_updated_at :datetime +# kind :integer not null +# last_run_at :datetime +# last_success_at :datetime +# vendor :string(255) +# created_at :datetime not null +# updated_at :datetime not null +# user_id :bigint(8) # # Indexes # @@ -50,40 +51,6 @@ class CheckTest < ActiveSupport::TestCase assert_nil notification.sent_at end - test "in_error? for recently added" do - check = build(:check, created_at: 1.day.ago) - refute check.in_error? - - check = build(:check, created_at: 1.day.ago, last_run_at: 3.minutes.ago) - refute check.in_error? - - check = build(:check, created_at: 1.day.ago, last_success_at: 1.hour.ago) - refute check.in_error? - end - - test "in_error? for never success check, with at least 1 run" do - check = build(:check, created_at: 3.weeks.ago, last_run_at: 1.day.ago) - assert check.in_error? - - check = build(:check, created_at: 3.weeks.ago, last_run_at: 4.days.ago) - assert check.in_error? - end - - test "in_error? ignore check without run" do - check = build(:check, created_at: 3.weeks.ago) - refute check.in_error? - end - - test "in_error? for last success a few days ago" do - check = build(:check, created_at: 3.weeks.ago, - last_success_at: 10.days.ago, last_run_at: 1.day.ago) - assert check.in_error? - - check = build(:check, created_at: 3.weeks.ago, - last_success_at: 1.days.ago, last_run_at: 1.day.ago) - refute check.in_error? - end - test "days_from_last_success without any success" do check = build(:check) assert_nil check.days_from_last_success diff --git a/test/services/check_processor_test.rb b/test/services/check_processor_test.rb index d5c1387..5804366 100644 --- a/test/services/check_processor_test.rb +++ b/test/services/check_processor_test.rb @@ -109,8 +109,8 @@ class CheckProcessorTest < ActiveSupport::TestCase create_list(:check, 3, :expires_next_week) configuration = Minitest::Mock.new - 2.times do configuration.expect(:long_term, 60) end - configuration.expect(:long_term_frequency, 10) + 2.times do configuration.expect(:long_term_interval, 300) end + configuration.expect(:long_term_frequency, 4) 3.times do configuration.expect(:interval, 0.000001) diff --git a/test/services/notifier/channels/base_test.rb b/test/services/notifier/channels/base_test.rb index 16856e9..aed7653 100644 --- a/test/services/notifier/channels/base_test.rb +++ b/test/services/notifier/channels/base_test.rb @@ -5,8 +5,8 @@ module Notifier class BaseTest < ActiveSupport::TestCase setup do class FakeChannel < Base - def supports?(reason, _notification) - reason != :unsupported + def supports?(notification) + notification.interval < 1_000 end def domain_notify_expires_soon(*); end @@ -18,7 +18,7 @@ module Notifier test "#notify change the status of the notification" do notification = create(:notification) - @channel.notify(:expires_soon, notification) + @channel.notify(notification) notification.reload @@ -26,18 +26,30 @@ module Notifier assert_just_now notification.sent_at end - test "#notify raises an exception for a invalid reason" do - notification = build(:notification) + test "#notify raises an exception for a non supported check kind" do + notification = Minitest::Mock.new + notification.expect :ongoing!, true + notification.expect :interval, 10 + + check = Minitest::Mock.new + check.expect(:kind, :invalid_kind) + check.expect(:kind, :invalid_kind) # twice (second call for exception message) + + notification.expect :check, check + notification.expect :check, check assert_raises ArgumentError do - @channel.notify(:unknown, notification) + @channel.notify(notification) end + + check.verify + notification.verify end - test "#notify does nothing when channel does not support a reason" do - notification = create(:notification) + test "#notify does nothing when channel doesn't support a notification whatever the reason" do + notification = create(:notification, interval: 10_000) - @channel.notify(:unsupported, notification) + @channel.notify(notification) notification.reload diff --git a/test/services/notifier/processor_test.rb b/test/services/notifier/processor_test.rb index c0aeaf6..92b41c1 100644 --- a/test/services/notifier/processor_test.rb +++ b/test/services/notifier/processor_test.rb @@ -22,8 +22,10 @@ module Notifier end test "#process_recurrent_failures respects the interval configuration between sends" do - create_list(:notification, 3, :email, check: build(:check, :last_runs_failed)) - test_interval_respected(:process_recurrent_failures, 3) + create_list(:check, 3, :last_runs_failed) + test_interval_respected(:process_recurrent_failures, 3) do |configuration| + configuration.expect(:consecutive_failures, 4.2) + end end private @@ -34,6 +36,9 @@ module Notifier count_expected.times do configuration.expect(:interval, 0.000001) end + + yield configuration if block_given? + processor = Processor.new(configuration) mock = Minitest::Mock.new diff --git a/test/services/notifier/resolver_test.rb b/test/services/notifier/resolver_test.rb index e43d474..2b291e7 100644 --- a/test/services/notifier/resolver_test.rb +++ b/test/services/notifier/resolver_test.rb @@ -6,58 +6,58 @@ module Notifier @resolver = Notifier::Resolver.new end - test "#resolve_expires_soon ignores user having notification disabled" do + test "#notifications_expiring_soon ignores user having notification disabled" do n1 = create(:notification, check: build(:check, :expires_next_week)) n1.check.user.update_attribute(:notifications_enabled, false) n2 = create(:notification, check: build(:check, :expires_next_week)) - notifications = @resolver.resolve_expires_soon + notifications = @resolver.notifications_expiring_soon assert_not_includes notifications, n1 assert_includes notifications, n2 end - test "#resolve_expires_soon ignores inactive checks" do + test "#notifications_expiring_soon ignores inactive checks" do n1 = create(:notification, check: build(:check, :expires_next_week, :inactive)) n2 = create(:notification, check: build(:check, :expires_next_week)) - notifications = @resolver.resolve_expires_soon + notifications = @resolver.notifications_expiring_soon assert_not_includes notifications, n1 assert_includes notifications, n2 end - test "#resolve_expires_soon gets only checks inside interval" do + test "#notifications_expiring_soon gets only checks inside interval" do n1 = create(:notification, check: build(:check, :expires_next_week), interval: 6) n2 = create(:notification, check: build(:check, :expires_next_week), interval: 7) - notifications = @resolver.resolve_expires_soon + notifications = @resolver.notifications_expiring_soon assert_not_includes notifications, n1 assert_includes notifications, n2 end - test "#resolve_expires_soon can gets several notifications for a same check" do + test "#notifications_expiring_soon can gets several notifications for a same check" do check = create(:check, :expires_next_week) n1 = create(:notification, check: check, interval: 3) n2 = create(:notification, check: check, interval: 10) n3 = create(:notification, check: check, interval: 30) - notifications = @resolver.resolve_expires_soon + notifications = @resolver.notifications_expiring_soon assert_not_includes notifications, n1 assert_includes notifications, n2 assert_includes notifications, n3 end - test "#resolve_expires_soon takes care of the status" do + test "#notifications_expiring_soon takes care of the status" do check = create(:check, :expires_next_week) n1 = create(:notification, check: check) n2 = create(:notification, :failed, check: check) n3 = create(:notification, :ongoing, check: check) n4 = create(:notification, :succeed, check: check) - notifications = @resolver.resolve_expires_soon + notifications = @resolver.notifications_expiring_soon assert_includes notifications, n1 assert_includes notifications, n2 @@ -65,49 +65,51 @@ module Notifier assert_not_includes notifications, n4 end - test "#resolve_expires_soon ignores checks expired and without date" do + test "#notifications_expiring_soon ignores checks expired and without date" do n1 = create(:notification, check: build(:check, :expires_next_week)) n2 = create(:notification, check: build(:check, domain_expires_at: 1.week.ago)) n3 = create(:notification, check: build(:check, :nil_dates)) - notifications = @resolver.resolve_expires_soon + notifications = @resolver.notifications_expiring_soon assert_includes notifications, n1 assert_not_includes notifications, n2 assert_not_includes notifications, n3 end - test "#resolve_check_failed ignores inactive checks" do - n1 = create(:notification, check: build(:check, :last_runs_failed, :inactive)) - n2 = create(:notification, check: build(:check, :last_runs_failed)) + test "#checks_recurrent_failures ignores inactive checks" do + c1 = create(:check, :last_runs_failed, :inactive) + c2 = create(:check, :last_runs_failed) - notifications = @resolver.resolve_check_failed + checks = @resolver.checks_recurrent_failures(4) - assert_not_includes notifications, n1 - assert_includes notifications, n2 + assert_not_includes checks, c1 + assert_includes checks, c2 end - test "#resolve_check_failed ignores user having notification disabled" do - n1 = create(:notification, check: build(:check, :last_runs_failed)) - n1.check.user.update_attribute(:notifications_enabled, false) - n2 = create(:notification, check: build(:check, :last_runs_failed)) + test "#checks_recurrent_failures ignores user having notification disabled" do + c1 = create(:check, :last_runs_failed) + c1.user.update_attribute(:notifications_enabled, false) + c2 = create(:check, :last_runs_failed) - notifications = @resolver.resolve_check_failed + checks = @resolver.checks_recurrent_failures(4) - assert_not_includes notifications, n1 - assert_includes notifications, n2 + assert_not_includes checks, c1 + assert_includes checks, c2 end - test "#resolve_check_failed gets only checks having last run in error" do - n1 = create(:notification, check: build(:check, :nil_dates)) - n2 = create(:notification, check: build(:check, :last_run_succeed)) - n3 = create(:notification, check: build(:check, :last_runs_failed)) + test "#checks_recurrent_failures gets only checks having consecutive failures" do + c1 = create(:check, :nil_dates) + c2 = create(:check, :last_run_succeed) + c3 = create(:check, :last_runs_failed, consecutive_failures: 5) + c4 = create(:check, :last_runs_failed, consecutive_failures: 3) - notifications = @resolver.resolve_check_failed + checks = @resolver.checks_recurrent_failures(4) - assert_not_includes notifications, n1 - assert_not_includes notifications, n2 - assert_includes notifications, n3 + assert_not_includes checks, c1 + assert_not_includes checks, c2 + assert_not_includes checks, c4 + assert_includes checks, c3 end end end