summaryrefslogtreecommitdiffstats
path: root/src/pybind/mgr/insights/tests
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
commite6918187568dbd01842d8d1d2c808ce16a894239 (patch)
tree64f88b554b444a49f656b6c656111a145cbbaa28 /src/pybind/mgr/insights/tests
parentInitial commit. (diff)
downloadceph-e6918187568dbd01842d8d1d2c808ce16a894239.tar.xz
ceph-e6918187568dbd01842d8d1d2c808ce16a894239.zip
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/pybind/mgr/insights/tests')
-rw-r--r--src/pybind/mgr/insights/tests/__init__.py0
-rw-r--r--src/pybind/mgr/insights/tests/test_health.py275
2 files changed, 275 insertions, 0 deletions
diff --git a/src/pybind/mgr/insights/tests/__init__.py b/src/pybind/mgr/insights/tests/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/pybind/mgr/insights/tests/__init__.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..06e6454f9
--- /dev/null
+++ b/src/pybind/mgr/insights/tests/test_health.py
@@ -0,0 +1,275 @@
+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())