mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2026-10-28 03:51:08 -04:00
3 files changed
+56
-2
No files matched your search
@@ -99,6 +99,19 @@ def apply_timezone(data, fields):
|
||||
# ===============================================================================
|
||||
# REPORTING
|
||||
# ===============================================================================
|
||||
MAX_ALERT_DOWN_MINUTES = 100 * 365 * 24 * 60
|
||||
|
||||
|
||||
def get_alert_down_minutes():
|
||||
"""Return NTFPRCS_alert_down_time as whole minutes clamped to
|
||||
0..MAX_ALERT_DOWN_MINUTES; a non-numeric value counts as 0."""
|
||||
try:
|
||||
minutes = int(get_setting_value("NTFPRCS_alert_down_time") or 0)
|
||||
except (TypeError, ValueError):
|
||||
return 0
|
||||
return max(0, min(minutes, MAX_ALERT_DOWN_MINUTES))
|
||||
|
||||
|
||||
def get_notifications(db):
|
||||
"""
|
||||
Fetch notifications for all configured sections.
|
||||
@@ -129,7 +142,7 @@ def get_notifications(db):
|
||||
|
||||
# Computed once and shared with NotificationInstance.clearPendingEmailFlag()
|
||||
# via conf, so the clear step acts on exactly the events selected here.
|
||||
alert_down_minutes = int(get_setting_value("NTFPRCS_alert_down_time") or 0)
|
||||
alert_down_minutes = get_alert_down_minutes()
|
||||
alert_down_cutoff = (
|
||||
timeNowUTC(as_string=False) - timedelta(minutes=alert_down_minutes)
|
||||
).strftime(DATETIME_PATTERN)
|
||||
|
||||
@@ -235,7 +235,8 @@ class NotificationInstance:
|
||||
def clearPendingEmailFlag(self):
|
||||
"""Clear evePendingAlertEmail on reported Events and stamp
|
||||
devLastNotification on their devices; 'Device Down' events are only
|
||||
cleared once NTFPRCS_alert_down_time minutes have passed."""
|
||||
cleared if older than conf.down_alert_cutoff, the cutoff
|
||||
get_notifications() used when selecting them."""
|
||||
|
||||
# Clean Pending Alert Events
|
||||
self.db.sql.execute("""
|
||||
|
||||
@@ -275,5 +275,45 @@ class TestClearPendingEmailFlagSelectionCutoff(unittest.TestCase):
|
||||
self.assertLessEqual(cutoff_dt, after - timedelta(minutes=5))
|
||||
|
||||
|
||||
class TestAlertDownTimeBounds(unittest.TestCase):
|
||||
"""An out-of-range NTFPRCS_alert_down_time must never raise out of
|
||||
get_notifications() (it runs inside the main monitoring loop)."""
|
||||
|
||||
def _run_get_notifications(self, raw_minutes):
|
||||
"""Run get_notifications() with the given raw setting value and return
|
||||
the recorded cutoff as a UTC datetime, restoring conf afterward."""
|
||||
mock_db = Mock()
|
||||
mock_json_obj = Mock()
|
||||
mock_json_obj.columnNames = []
|
||||
mock_json_obj.json = {"data": []}
|
||||
mock_db.get_table_as_json.return_value = mock_json_obj
|
||||
settings = {
|
||||
"NTFPRCS_INCLUDED_SECTIONS": ["down_devices"],
|
||||
"NTFPRCS_alert_down_time": raw_minutes,
|
||||
}
|
||||
original_cutoff = conf.down_alert_cutoff
|
||||
try:
|
||||
with patch(
|
||||
"messaging.reporting.get_setting_value",
|
||||
side_effect=lambda key: settings.get(key, ""),
|
||||
):
|
||||
get_notifications(mock_db)
|
||||
cutoff = conf.down_alert_cutoff
|
||||
finally:
|
||||
conf.down_alert_cutoff = original_cutoff
|
||||
return datetime.strptime(cutoff, DATETIME_PATTERN).replace(tzinfo=timezone.utc)
|
||||
|
||||
def test_huge_value_does_not_raise(self):
|
||||
"""A value too large for timedelta/datetime must be bounded, not raise
|
||||
OverflowError."""
|
||||
cutoff = self._run_get_notifications("999999999999999")
|
||||
self.assertLess(cutoff, timeNowUTC(as_string=False))
|
||||
|
||||
def test_negative_value_does_not_produce_future_cutoff(self):
|
||||
"""A negative window must not push the cutoff into the future."""
|
||||
cutoff = self._run_get_notifications("-5")
|
||||
self.assertLessEqual(cutoff, timeNowUTC(as_string=False))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user