aboutsummaryrefslogtreecommitdiff
path: root/test/alert_and_notification_logic.rb
diff options
context:
space:
mode:
Diffstat (limited to 'test/alert_and_notification_logic.rb')
-rw-r--r--test/alert_and_notification_logic.rb391
1 files changed, 391 insertions, 0 deletions
diff --git a/test/alert_and_notification_logic.rb b/test/alert_and_notification_logic.rb
new file mode 100644
index 0000000..19b2478
--- /dev/null
+++ b/test/alert_and_notification_logic.rb
@@ -0,0 +1,391 @@
+# Mauve server tests - alerts and notification logic. Define the basic workings
+# so that we know what should happen when we send sequences of alerts at
+# different times.
+#
+# These aren't really unit tests, just narrative specifications as to what
+# should happen under what stimuli. I suspect I will break these down into
+# smaller units if things break under otherwise difficult conditions.
+#
+
+$: << __FILE__.split("/")[0..-2].join("/")
+require 'test/unit'
+require 'mauve_test_helper'
+require 'mauve_time'
+
+class AlertAndNotificationLogic < Test::Unit::TestCase
+ include MauveTestHelper
+
+ def configuration_template
+ <<-TEMPLATE
+ # This is the head of all the configuration files. Filenames are relative
+ # to the cwd, which is assumed to be a fleeting test directory.
+
+ server {
+ ip "127.0.0.1"
+ port #{@port_alerts ||= 44444}
+ log_file ENV['TEST_LOG'] ? STDOUT : "#{dir}/log"
+ log_level 0
+ database "sqlite3:///#{dir}/mauve_test.db"
+ transmission_id_expire_time 600
+
+ # doesn't restart nicely at the moment
+ #web_interface {
+ # port #{@port_web ||= 44444}
+ #}
+ }
+
+ #
+ # All notifications are sent to files which we can open up and check during
+ # our tests. Network delivery is not tested in this script.
+ #
+
+ notification_method("xmpp") {
+ deliver_to_queue AlertAndNotificationLogic::Notifications
+ deliver_to_file "#{dir}/xmpp.txt"
+ disable_normal_delivery!
+
+ jid "mauveserv@chat.bytemark.co.uk"
+ password "foo"
+ }
+
+ notification_method("email") {
+ deliver_to_queue AlertAndNotificationLogic::Notifications
+ deliver_to_file "#{dir}/email.txt"
+ disable_normal_delivery!
+
+ # add in SMTP server, username, password etc.
+ # default to sending through localhost
+ from "matthew@bytemark.co.uk"
+ server "bytemail.bytemark.co.uk"
+ subject_prefix "[Bytemark alerts] "
+
+ }
+
+ notification_method("sms") {
+ provider "AQL"
+ deliver_to_queue AlertAndNotificationLogic::Notifications
+ deliver_to_file "#{dir}/sms.txt"
+ disable_normal_delivery!
+
+ username "x"
+ password "x"
+ from "01904890890"
+ max_messages_per_alert 3
+ }
+
+ # a person common to all our tests
+
+ person("joe_bloggs") {
+ urgent { sms("12345") }
+ normal { email("12345@joe_bloggs.email") }
+ low { xmpp("12345@joe_bloggs.xmpp") }
+ }
+
+ person("jimmy_junior") {
+ urgent { sms("66666") }
+ normal { email("jimmy@junior.email") }
+ low { email("jimmy@junior.email") }
+ }
+
+ alert_group {
+ includes { source == "rare-and-important" }
+ acknowledgement_time 60.minutes
+ level URGENT
+
+ notify("joe_bloggs") { every 10.minutes }
+ }
+
+ alert_group {
+ includes { source == "noisy-and-annoying" || alert_id == "whine" }
+ acknowledgement_time 24.hours
+ level LOW
+
+ notify("jimmy_junior") { every 2.hours }
+ notify("joe_bloggs") {
+ every 30.minutes
+ during {
+ unacknowledged 6.hours
+ }
+ }
+ }
+
+ alert_group {
+ includes { source == "can-wait-until-monday" }
+ level NORMAL
+
+ notify("jimmy_junior") {
+ every 30.minutes
+ during { days_in_week(1..5) && hours_in_day(9..5) }
+ }
+ notify("joe_bloggs") {
+ every 2.hours
+ during { days_in_week(1..5) && hours_in_day(9..5) }
+ }
+ }
+
+ # catch-all
+ alert_group {
+ acknowledgement_time 1.minute
+ level NORMAL
+
+ notify("joe_bloggs") { every 1.hour }
+ }
+ TEMPLATE
+ end
+
+ def setup
+ start_server(configuration_template)
+ end
+
+ def teardown
+ stop_server
+ # no tests should leave notifications on the stack
+ assert_no_notification
+ end
+
+ # Raise one alert, check representation in database, and that alert is
+ # received as expected.
+ #
+ def test_basic_fields_are_recognised
+ mauvesend("-o my_source -i alert1 -s \"alert1 summary\" -d \"alert1 detail\" -u \"alert1 subject\"")
+
+ assert_not_nil(alert = Alert.first)
+ assert_equal("my_source", alert.source)
+ assert_equal("alert1", alert.alert_id)
+ assert_equal("alert1 summary", alert.summary)
+ assert_equal("alert1 detail", alert.detail)
+ assert_equal("alert1 subject", alert.subject)
+ assert(alert.raised?)
+ assert(!alert.cleared?)
+ assert(!alert.acknowledged?)
+
+ with_next_notification do |destination, this_alert, other_alerts|
+ assert_equal("12345@joe_bloggs.email", destination)
+ assert_equal(Alert.first, this_alert)
+ assert_equal([Alert.first], other_alerts)
+ end
+
+ end
+
+ # Check that a simple automatic raise, acknowledge & auto-clear request
+ # work properly.
+ #
+ def test_auto_raise_and_clear
+ # Raise the alert, wait for it to be processed
+ mauvesend("-o my_source -i alert1 -s \"alert1 summary\" -d \"alert1 detail\" -u \"alert1 subject\" -r +5m -c +10m")
+
+ # Check internal state
+ #
+ assert(!Alert.first.raised?, "Auto-raising alert raised early")
+ assert(!Alert.first.cleared?, "Auto-clearing alert cleared early")
+ assert(!Alert.first.acknowledged?, "Alert acknowledged when I didn't expect it")
+
+ # We asked for it to be raised in 5 minutes, so no alert yet...
+ #
+ assert_no_notification
+
+ # Push forward to when the alert should be raised, check it has been
+ #
+ Time.advance(5.minutes)
+ assert(Alert.first.raised?, "#{Alert.first.inspect} should be raised by now")
+ assert(!Alert.first.cleared?, "#{Alert.first.inspect} should not be cleared")
+
+ # Check that we have a notification
+ #
+ with_next_notification do |destination, this_alert, other_alerts|
+ assert_equal("12345@joe_bloggs.email", destination)
+ assert_equal(Alert.first, this_alert)
+ assert_equal('raised', this_alert.update_type)
+ end
+
+ # Simulate manual acknowledgement
+ #
+ Alert.first.acknowledge!(Configuration.current.people["joe_bloggs"])
+ Timers.restart_and_then_wait_until_idle
+ assert(Alert.first.acknowledged?, "Acknowledgement didn't work")
+
+ # Check that the acknowledgement has caused a notification
+ #
+ with_next_notification do |destination, this_alert, other_alerts|
+ assert_equal("12345@joe_bloggs.email", destination)
+ assert_equal(Alert.first, this_alert)
+ assert_equal('acknowledged', this_alert.update_type, this_alert.inspect)
+ end
+ assert(Alert.first.acknowledged?)
+ assert(Alert.first.raised?)
+ assert(!Alert.first.cleared?)
+
+ # Now with the config set to un-acknowledge alerts after only 1 minute,
+ # try winding time on and check that this happens.
+ #
+ Time.advance(2.minutes)
+ with_next_notification do |destination, this_alert, other_alerts|
+ assert_equal("12345@joe_bloggs.email", destination)
+ assert_equal(Alert.first, this_alert)
+ assert_equal('raised', this_alert.update_type, this_alert.inspect)
+ end
+
+ # Check that auto-clearing works four minutes later
+ #
+ Time.advance(5.minutes)
+ assert(Alert.first.cleared?)
+ assert(!Alert.first.raised?)
+
+ # Finally check for a notification that auto-clearing has happened
+ #
+ with_next_notification do |destination, this_alert, other_alerts|
+ assert_equal("12345@joe_bloggs.email", destination)
+ assert_equal(Alert.first, this_alert)
+ assert_equal('cleared', this_alert.update_type, this_alert.inspect)
+ end
+
+ # And see that no further reminders are sent a while later
+ Time.advance(1.day)
+ assert_no_notification
+ end
+
+ def test_one_alert_changes_from_outside
+ # Raise our test alert, wait for it to be processed
+ mauvesend("-o my_source -i alert1 -s \"alert1 summary\" -d \"alert1 detail\" -u \"alert1 subject\"")
+
+ # Check internal representation, external notification
+ #
+ assert(Alert.first.raised?)
+ assert(!Alert.first.cleared?)
+ with_next_notification do |destination, this_alert, other_alerts|
+ assert_equal('raised', this_alert.update_type, this_alert.inspect)
+ end
+
+ # Check we get reminders every hour, and no more
+ #
+ 12.times do
+ Time.advance(1.hour)
+ with_next_notification do |destination, this_alert, other_alerts|
+ assert_equal('raised', this_alert.update_type, this_alert.inspect)
+ end
+ assert_no_notification
+ end
+
+ # Clear the alert, wait for it to be processed
+ mauvesend("-o my_source -i alert1 -c now")
+ assert(!Alert.first.raised?)
+ assert(Alert.first.cleared?)
+ with_next_notification do |destination, this_alert, other_alerts|
+ assert_equal('cleared', this_alert.update_type, this_alert.inspect)
+ end
+
+ # Check we can raise the same alert again
+ Time.advance(1.minute)
+ mauvesend("-o my_source -i alert1 -s \"alert1 summary\" -d \"alert1 detail\" -u \"alert1 subject\" -r now")
+ assert(Alert.first.raised?, Alert.first.inspect)
+ assert(!Alert.first.cleared?, Alert.first.inspect)
+ with_next_notification do |destination, this_alert, other_alerts|
+ assert_equal('raised', this_alert.update_type, this_alert.inspect)
+ end
+ end
+
+ def test_alert_groups
+ # check that this alert is reminded more often than normal
+ mauvesend("-o rare-and-important -i alert1 -s \"rare and important alert\"")
+ assert(Alert.first.raised?)
+ assert(!Alert.first.cleared?)
+
+ 10.times do
+ with_next_notification do |destination, this_alert, other_alerts|
+ assert_equal('raised', this_alert.update_type, this_alert.inspect)
+ assert_equal('12345', destination)
+ Time.advance(10.minutes)
+ end
+ end
+ discard_next_notification
+ end
+
+ def test_future_raising
+ mauvesend("-i heartbeat -c now -r +10m -s \"raise in the future\"")
+ assert(!Alert.first.raised?)
+ assert(Alert.first.cleared?)
+ assert_no_notification
+
+ # Check the future alert goes off
+ #
+ Time.advance(10.minutes)
+ assert(Alert.first.raised?)
+ assert(!Alert.first.cleared?)
+ with_next_notification do |destination, this_alert, other_alerts|
+ assert_equal('raised', this_alert.update_type, this_alert.inspect)
+ end
+
+ # Check that a repeat of the "heartbeat" update clears it, and we get
+ # a notification.
+ #
+ mauvesend("-i heartbeat -c now -r +10m -s \"raise in the future\"")
+ assert(!Alert.first.raised?)
+ assert(Alert.first.cleared?)
+ with_next_notification do |destination, this_alert, other_alerts|
+ assert_equal('cleared', this_alert.update_type, this_alert.inspect)
+ end
+
+ # Check that a re-send of the same clear alert doesn't send another
+ # notification
+ #
+ Time.advance(1.minute)
+ mauvesend("-i heartbeat -c now -r +10m -s \"raise in the future\"")
+ assert(!Alert.first.raised?)
+ assert(Alert.first.cleared?)
+ assert_no_notification
+
+ # Check that a skewed resend doesn't confuse it
+ #
+ mauvesend("-i heartbeat -c +1m -r +11m -s \"raise in the future\"")
+ assert(!Alert.first.raised?)
+ assert(Alert.first.cleared?)
+ Time.advance(1.minute)
+ assert(!Alert.first.raised?)
+ assert(Alert.first.cleared?)
+ assert_no_notification
+ end
+
+ # Make sure that using the "replace all flag" works as expected.
+ #
+ def test_replace_flag
+ mauvesend("-p")
+ #mauvesend("-p")
+ assert_no_notification
+
+ mauvesend("-i test1 -s\"\test1\"")
+ assert(Alert.first.raised?)
+ with_next_notification do |destination, this_alert, other_alerts|
+ assert_equal('raised', this_alert.update_type, this_alert.inspect)
+ end
+ assert_no_notification
+
+ mauvesend("-p")
+ #mauvesend("-p")
+ with_next_notification do |destination, this_alert, other_alerts|
+ assert_equal('cleared', this_alert.update_type, this_alert.inspect)
+ end
+ assert_no_notification
+ end
+
+ def test_earliest_date
+ alert = Alert.create!(
+ :alert_id => "test_id",
+ :source => "test1",
+ :subject => "test subject",
+ :summary => "test summary",
+ :raised_at => nil,
+ :will_raise_at => Time.now + 60,
+ :will_clear_at => Time.now + 120,
+ :update_type => "cleared",
+ :updated_at => Time.now
+ )
+ assert(alert)
+
+ assert(AlertEarliestDate.first.alert == alert)
+ end
+
+end
+
+
+
+