# 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