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 from tests.util import assert_called_once 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): assert monitor.last_output is None with patch.object(monitor, "failure") as mock_failure: monitor.command = ["ls", "--not-real"] assert not monitor.check() assert_called_once(mock_failure) assert monitor.last_output is not None def test_monitor_check_success(self, monitor): assert monitor.last_output is None with patch.object(monitor, "success") as mock_success: assert monitor.check() assert_called_once(mock_success) assert monitor.last_output is not None @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