minitor/tests/monitor_test.py
Ian Fijolek aad28976e2 Add alerting for recovered monitors
Based on the idea from SeaLife, adds alerts for when a monitor comes out
of an alerting down state. Also includes a bunch of unit tests to cover
the new code.
2018-04-14 17:27:37 -07:00

142 lines
4.3 KiB
Python

from datetime import datetime
from unittest.mock import patch
import pytest
from minitor.main import InvalidMonitorException
from minitor.main import MinitorAlert
from minitor.main import Monitor
from minitor.main import validate_monitor_settings
class TestMonitor(object):
@pytest.fixture
def monitor(self):
return Monitor({
'name': 'Sample Monitor',
'command': ['echo', 'foo'],
'alert_down': ['log'],
'alert_up': ['log'],
'check_interval': 1,
'alert_after': 1,
'alert_every': 1,
})
@pytest.mark.parametrize('settings', [
{'alert_after': 0},
{'alert_every': 0},
{'check_interval': 0},
{'alert_after': 'invalid'},
{'alert_every': 'invalid'},
{'check_interval': 'invalid'},
])
def test_monitor_invalid_configuration(self, settings):
with pytest.raises(InvalidMonitorException):
validate_monitor_settings(settings)
@pytest.mark.parametrize(
'alert_after',
[1, 20],
ids=lambda arg: 'alert_after({})'.format(arg),
)
@pytest.mark.parametrize(
'alert_every',
[-1, 1, 2, 1440],
ids=lambda arg: 'alert_every({})'.format(arg),
)
def test_monitor_alert_after(self, monitor, alert_after, alert_every):
monitor.alert_after = alert_after
monitor.alert_every = alert_every
# fail a bunch of times before the final failure
for _ in range(alert_after - 1):
monitor.failure()
# this time should raise an alert
with pytest.raises(MinitorAlert):
monitor.failure()
@pytest.mark.parametrize(
'alert_after',
[1, 20],
ids=lambda arg: 'alert_after({})'.format(arg),
)
@pytest.mark.parametrize(
'alert_every',
[1, 2, 1440],
ids=lambda arg: 'alert_every({})'.format(arg),
)
def test_monitor_alert_every(self, monitor, alert_after, alert_every):
monitor.alert_after = alert_after
monitor.alert_every = alert_every
# fail a bunch of times before the final failure
for _ in range(alert_after - 1):
monitor.failure()
# this time should raise an alert
with pytest.raises(MinitorAlert):
monitor.failure()
# fail a bunch more times until the next alert
for _ in range(alert_every - 1):
monitor.failure()
# this failure should alert now
with pytest.raises(MinitorAlert):
monitor.failure()
def test_monitor_alert_every_exponential(self, monitor):
monitor.alert_after = 1
monitor.alert_every = -1
failure_count = 16
expect_failures_on = {1, 2, 4, 8, 16}
for i in range(failure_count):
if i + 1 in expect_failures_on:
with pytest.raises(MinitorAlert):
monitor.failure()
else:
monitor.failure()
@pytest.mark.parametrize('last_check', [None, datetime(2018, 4, 10)])
def test_monitor_should_check(self, monitor, last_check):
monitor.last_check = last_check
assert monitor.should_check()
def test_monitor_check_fail(self, monitor):
with patch.object(monitor, 'failure') as mock_failure:
monitor.command = ['ls', '--not-real']
assert not monitor.check()
mock_failure.assert_called_once()
def test_monitor_check_success(self, monitor):
with patch.object(monitor, 'success') as mock_success:
assert monitor.check()
mock_success.assert_called_once()
@pytest.mark.parametrize('failure_count', [0, 1])
def test_monitor_success(self, monitor, failure_count):
monitor.alert_count = 0
monitor.total_failure_count = failure_count
assert monitor.last_success is None
monitor.success()
assert monitor.alert_count == 0
assert monitor.last_success is not None
assert monitor.total_failure_count == 0
def test_monitor_success_back_up(self, monitor):
monitor.total_failure_count = 1
monitor.alert_count = 1
with pytest.raises(MinitorAlert):
monitor.success()
assert monitor.alert_count == 0
assert monitor.last_success is not None
assert monitor.total_failure_count == 0