From 19fcec84d8d7d21e796c7624e521b60d28ee21ed Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 20:45:59 +0200 Subject: Adding upstream version 16.2.11+ds. Signed-off-by: Daniel Baumann --- src/pybind/mgr/insights/tests/test_health.py | 273 +++++++++++++++++++++++++++ 1 file changed, 273 insertions(+) create mode 100644 src/pybind/mgr/insights/tests/test_health.py (limited to 'src/pybind/mgr/insights/tests/test_health.py') diff --git a/src/pybind/mgr/insights/tests/test_health.py b/src/pybind/mgr/insights/tests/test_health.py new file mode 100644 index 000000000..c39e1097d --- /dev/null +++ b/src/pybind/mgr/insights/tests/test_health.py @@ -0,0 +1,273 @@ +import unittest +from tests import mock +from ..health import * + +class HealthChecksTest(unittest.TestCase): + def test_check_accum_empty(self): + # health checks accum initially empty reports empty + h = HealthCheckAccumulator() + self.assertEqual(h.checks(), {}) + + h = HealthCheckAccumulator({}) + self.assertEqual(h.checks(), {}) + + def _get_init_checks(self): + return HealthCheckAccumulator({ + "C0": { + "S0": { + "summary": ["s0", "s1"], + "detail": ("d0", "d1") + } + } + }) + + def test_check_init(self): + # initialization with lists and tuples is OK + h = self._get_init_checks() + self.assertEqual(h.checks(), { + "C0": { + "S0": { + "summary": set(["s0", "s1"]), + "detail": set(["d0", "d1"]) + } + } + }) + + def _get_merged_checks(self): + h = self._get_init_checks() + h.merge(HealthCheckAccumulator({ + "C0": { + "S0": { + "summary": ["s0", "s1", "s2"], + "detail": ("d2",) + }, + "S1": { + "summary": ["s0", "s1", "s2"], + "detail": () + } + }, + "C1": { + "S0": { + "summary": [], + "detail": ("d0", "d1", "d2") + } + } + })) + return h + + def test_check_merge(self): + # merging combines and de-duplicates + h = self._get_merged_checks() + self.assertEqual(h.checks(), { + "C0": { + "S0": { + "summary": set(["s0", "s1", "s2"]), + "detail": set(["d0", "d1", "d2"]) + }, + "S1": { + "summary": set(["s0", "s1", "s2"]), + "detail": set([]) + } + }, + "C1": { + "S0": { + "summary": set([]), + "detail": set(["d0", "d1", "d2"]) + } + } + }) + + def test_check_add_no_change(self): + # returns false when nothing changes + h = self._get_merged_checks() + + self.assertFalse(h.add({})) + + self.assertFalse(h.add({ + "C0": { + "severity": "S0", + "summary": { "message": "s0" }, + "detail": [] + } + })) + + self.assertFalse(h.add({ + "C0": { + "severity": "S0", + "summary": { "message": "s1" }, + "detail": [{ "message": "d1" }] + } + })) + + self.assertFalse(h.add({ + "C0": { + "severity": "S0", + "summary": { "message": "s0" }, + "detail": [{ "message": "d1" }, { "message": "d2" }] + } + })) + + def test_check_add_changed(self): + # new checks report change + h = self._get_merged_checks() + + self.assertTrue(h.add({ + "C0": { + "severity": "S0", + "summary": { "message": "s3" }, + "detail": [] + } + })) + + self.assertTrue(h.add({ + "C0": { + "severity": "S0", + "summary": { "message": "s1" }, + "detail": [{ "message": "d4" }] + } + })) + + self.assertTrue(h.add({ + "C0": { + "severity": "S2", + "summary": { "message": "s0" }, + "detail": [{ "message": "d0" }] + } + })) + + self.assertTrue(h.add({ + "C2": { + "severity": "S0", + "summary": { "message": "s0" }, + "detail": [{ "message": "d0" }, { "message": "d1" }] + } + })) + + self.assertEqual(h.checks(), { + "C0": { + "S0": { + "summary": set(["s0", "s1", "s2", "s3"]), + "detail": set(["d0", "d1", "d2", "d4"]) + }, + "S1": { + "summary": set(["s0", "s1", "s2"]), + "detail": set([]) + }, + "S2": { + "summary": set(["s0"]), + "detail": set(["d0"]) + } + }, + "C1": { + "S0": { + "summary": set([]), + "detail": set(["d0", "d1", "d2"]) + } + }, + "C2": { + "S0": { + "summary": set(["s0"]), + "detail": set(["d0", "d1"]) + } + } + }) + +class HealthHistoryTest(unittest.TestCase): + def _now(self): + # return some time truncated at 30 minutes past the hour. this lets us + # fiddle with time offsets without worrying about accidentally landing + # on exactly the top of the hour which is the edge of a time slot for + # tracking health history. + dt = datetime.datetime.utcnow() + return datetime.datetime( + year = dt.year, + month = dt.month, + day = dt.day, + hour = dt.hour, + minute = 30) + + def test_empty_slot(self): + now = self._now() + + HealthHistorySlot._now = mock.Mock(return_value=now) + h = HealthHistorySlot() + + # reports no historical checks + self.assertEqual(h.health(), { "checks": {} }) + + # an empty slot doesn't need to be flushed + self.assertFalse(h.need_flush()) + + def test_expires(self): + now = self._now() + + HealthHistorySlot._now = mock.Mock(return_value=now) + h = HealthHistorySlot() + self.assertFalse(h.expired()) + + # an hour from now it would be expired + future = now + datetime.timedelta(hours = 1) + HealthHistorySlot._now = mock.Mock(return_value=future) + self.assertTrue(h.expired()) + + def test_need_flush(self): + now = self._now() + + HealthHistorySlot._now = mock.Mock(return_value=now) + h = HealthHistorySlot() + self.assertFalse(h.need_flush()) + + self.assertTrue(h.add(dict(checks = { + "C0": { + "severity": "S0", + "summary": { "message": "s0" }, + "detail": [{ "message": "d0" }] + } + }))) + # no flush needed, yet... + self.assertFalse(h.need_flush()) + + # after persist period time elapses, a flush is needed + future = now + PERSIST_PERIOD + HealthHistorySlot._now = mock.Mock(return_value=future) + self.assertTrue(h.need_flush()) + + # mark flush resets + h.mark_flushed() + self.assertFalse(h.need_flush()) + + def test_need_flush_edge(self): + # test needs flush is true because it has expired, not because it has + # been dirty for the persistence period + dt = datetime.datetime.utcnow() + now = datetime.datetime( + year = dt.year, + month = dt.month, + day = dt.day, + hour = dt.hour, + minute = 59, + second = 59) + HealthHistorySlot._now = mock.Mock(return_value=now) + h = HealthHistorySlot() + self.assertFalse(h.expired()) + self.assertFalse(h.need_flush()) + + # now it is dirty, but it doesn't need a flush + self.assertTrue(h.add(dict(checks = { + "C0": { + "severity": "S0", + "summary": { "message": "s0" }, + "detail": [{ "message": "d0" }] + } + }))) + self.assertFalse(h.expired()) + self.assertFalse(h.need_flush()) + + # advance time past the hour so it expires, but not past the persistence + # period deadline for the last event that set the dirty bit + self.assertTrue(PERSIST_PERIOD.total_seconds() > 5) + future = now + datetime.timedelta(seconds = 5) + HealthHistorySlot._now = mock.Mock(return_value=future) + + self.assertTrue(h.expired()) + self.assertTrue(h.need_flush()) -- cgit v1.2.3