diff --git a/app/models/blazer/check.rb b/app/models/blazer/check.rb
index 5f14ecad2..6a796a2a2 100644
--- a/app/models/blazer/check.rb
+++ b/app/models/blazer/check.rb
@@ -49,7 +49,7 @@ def update_state(result)
"passing"
end
elsif result.rows.any?
- check_type == "missing_data" ? "passing" : "failing"
+ %w[bad_data new_bad_data].include?(check_type) ? 'failing' : 'passing'
else
check_type == "missing_data" ? "failing" : "passing"
end
@@ -66,8 +66,16 @@ def update_state(result)
end
end
+ condition = state != state_was
+
+ if respond_to?(:last_results_hash)
+ results_hash = Digest::MD5.hexdigest(result.rows.to_json)
+ condition = results_hash != last_result if check_type == 'new_bad_data'
+ self.last_results_hash = results_hash
+ end
+
# do not notify on creation, except when not passing
- if (state_was != "new" || state != "passing") && state != state_was
+ if (state_was != "new" || state != "passing") && condition
Blazer::CheckMailer.state_change(self, state, state_was, result.rows.size, message, result.columns, result.rows.first(10).as_json, result.column_types, check_type).deliver_now if emails.present?
Blazer::SlackNotifier.state_change(self, state, state_was, result.rows.size, message, check_type)
end
diff --git a/app/views/blazer/check_mailer/state_change.html.erb b/app/views/blazer/check_mailer/state_change.html.erb
index dce9ac61d..34323125a 100644
--- a/app/views/blazer/check_mailer/state_change.html.erb
+++ b/app/views/blazer/check_mailer/state_change.html.erb
@@ -6,7 +6,7 @@
<%= link_to "View", query_url(@check.query_id) %>
<% if @error %>
<%= @error %>
- <% elsif @rows_count > 0 && @check_type == "bad_data" %>
+ <% elsif @rows_count > 0 && %w[bad_data new_bad_data].include?(@check_type) %>
<% if @rows_count <= 10 %>
<%= pluralize(@rows_count, "row") %>
diff --git a/app/views/blazer/checks/_form.html.erb b/app/views/blazer/checks/_form.html.erb
index 3e6020604..c555f5962 100644
--- a/app/views/blazer/checks/_form.html.erb
+++ b/app/views/blazer/checks/_form.html.erb
@@ -25,6 +25,7 @@
<%= f.label :check_type, "Alert if" %>
<% check_options = [["Any results (bad data)", "bad_data"], ["No results (missing data)", "missing_data"]] %>
+ <% check_options << ["Any new results (more bad data)", "new_bad_data"] if @check.respond_to?(:last_results_hash) %>
<% check_options << ["Anomaly (most recent data point)", "anomaly"] if Blazer.anomaly_checks %>
<%= f.select :check_type, check_options %>
diff --git a/lib/blazer/slack_notifier.rb b/lib/blazer/slack_notifier.rb
index 8a03d5f06..c724a850f 100644
--- a/lib/blazer/slack_notifier.rb
+++ b/lib/blazer/slack_notifier.rb
@@ -7,7 +7,7 @@ def self.state_change(check, state, state_was, rows_count, error, check_type)
text =
if error
error
- elsif rows_count > 0 && check_type == "bad_data"
+ elsif rows_count > 0 && %w[bad_data new_bad_data].include?(check_type)
pluralize(rows_count, "row")
end
diff --git a/lib/generators/blazer/templates/install.rb.tt b/lib/generators/blazer/templates/install.rb.tt
index bf1999303..f968e46d1 100644
--- a/lib/generators/blazer/templates/install.rb.tt
+++ b/lib/generators/blazer/templates/install.rb.tt
@@ -39,6 +39,7 @@ class <%= migration_class_name %> < ActiveRecord::Migration<%= migration_version
t.text :emails
t.text :slack_channels
t.string :check_type
+ t.string :last_results_hash
t.text :message
t.datetime :last_run_at
t.timestamps null: false
diff --git a/test/checks_test.rb b/test/checks_test.rb
index c87934ead..71e4c350b 100644
--- a/test/checks_test.rb
+++ b/test/checks_test.rb
@@ -66,6 +66,25 @@ def test_emails
end
end
+ def test_emails_for_new_bad_data
+ query = create_query
+ check = create_check(query: query, check_type: "new_bad_data", emails: "hi@example.org,hi2@example.org")
+
+ assert_emails 1 do
+ Blazer.run_checks(schedule: "5 minutes")
+ end
+
+ assert_emails 0 do
+ Blazer.run_checks(schedule: "5 minutes")
+ end
+
+ query.update!(statement: "SELECT 1 LIMIT 0")
+
+ assert_emails 1 do
+ Blazer.run_checks(schedule: "5 minutes")
+ end
+ end
+
def test_slack
query = create_query
check = create_check(query: query, check_type: "bad_data", slack_channels: "#general,#random")
@@ -83,6 +102,25 @@ def test_slack
end
end
+ def test_slack_for_new_bad_data
+ query = create_query
+ check = create_check(query: query, check_type: "new_bad_data", slack_channels: "#general,#random")
+
+ assert_slack_messages 2 do
+ Blazer.run_checks(schedule: "5 minutes")
+ end
+
+ assert_slack_messages 0 do
+ Blazer.run_checks(schedule: "5 minutes")
+ end
+
+ query.update!(statement: "SELECT 1 LIMIT 0")
+
+ assert_slack_messages 2 do
+ Blazer.run_checks(schedule: "5 minutes")
+ end
+ end
+
def assert_slack_messages(expected)
count = 0
Blazer::SlackNotifier.stub :post_api, ->(*) { count += 1 } do
diff --git a/test/internal/db/schema.rb b/test/internal/db/schema.rb
index b8355bfe8..30ffcf2c2 100644
--- a/test/internal/db/schema.rb
+++ b/test/internal/db/schema.rb
@@ -38,6 +38,7 @@
t.text :emails
t.text :slack_channels
t.string :check_type
+ t.string :last_results_hash
t.text :message
t.datetime :last_run_at
t.timestamps null: false