]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
mgr/osd_support: add unittests
authorJoshua Schmid <jschmid@suse.de>
Thu, 9 Jul 2020 09:40:54 +0000 (11:40 +0200)
committerJoshua Schmid <jschmid@suse.de>
Thu, 9 Jul 2020 13:06:17 +0000 (15:06 +0200)
Signed-off-by: Joshua Schmid <jschmid@suse.de>
src/pybind/mgr/osd_support/__init__.py
src/pybind/mgr/osd_support/module.py
src/pybind/mgr/osd_support/tests/__init__.py [new file with mode: 0644]
src/pybind/mgr/osd_support/tests/fixtures.py [new file with mode: 0644]
src/pybind/mgr/osd_support/tests/test_osd_support.py [new file with mode: 0644]

index 88ed2b9f57c177619f8e1e06c61091763c44dcdc..f4f9e26e0643fd4a1d94a6cd103e22f7ba41fb8d 100644 (file)
@@ -1 +1,7 @@
+import os
+
+if 'UNITTEST' in os.environ:
+    import tests
+    tests.mock_ceph_modules()  # type: ignore
+
 from .module import OSDSupport
index 5b743200e003e779d8387e097d566d1d671d1332..a219ca868cc626ccaf7c792a9f921aa50736c6ec 100644 (file)
@@ -188,10 +188,13 @@ class OSDSupport(MgrModule):
         self.run = False
         self.event.set()
 
+    def get_osds_in_cluster(self) -> List[str]:
+        osd_map = self.get_osdmap()
+        return [x.get('osd') for x in osd_map.dump().get('osds', [])]
+
     def osds_not_in_cluster(self, osd_ids: List[int]) -> Set[int]:
         self.log.info(f"Checking if provided osds <{osd_ids}> exist in the cluster")
-        osd_map = self.get_osdmap()
-        cluster_osds = [x.get('osd') for x in osd_map.dump().get('osds', [])]
+        cluster_osds = self.get_osds_in_cluster()
         not_in_cluster = set()
         for osd_id in osd_ids:
             if int(osd_id) not in cluster_osds:
@@ -235,7 +238,7 @@ class OSDSupport(MgrModule):
             osd_df = self.osd_df()
         osd_nodes = osd_df.get('nodes', [])
         for osd_node in osd_nodes:
-            if osd_node.get('id', None) == int(osd_id):
+            if osd_node.get('id') == int(osd_id):
                 return osd_node.get('pgs', -1)
         return -1
 
@@ -243,8 +246,9 @@ class OSDSupport(MgrModule):
         osd_df = self.osd_df()
         osd_nodes = osd_df.get('nodes', [])
         for osd_node in osd_nodes:
-            if osd_node.get('id', None) == int(osd_id):
-                return float(osd_node.get('crush_weight'))
+            if osd_node.get('id') == int(osd_id):
+                if 'crush_weight' in osd_node:
+                    return float(osd_node.get('crush_weight'))
         return -1.0
 
     def reweight_osd(self, osd_id: int, weight: float = 0.0) -> bool:
diff --git a/src/pybind/mgr/osd_support/tests/__init__.py b/src/pybind/mgr/osd_support/tests/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/pybind/mgr/osd_support/tests/fixtures.py b/src/pybind/mgr/osd_support/tests/fixtures.py
new file mode 100644 (file)
index 0000000..e948a3a
--- /dev/null
@@ -0,0 +1,14 @@
+from osd_support import OSDSupport
+import pytest
+
+from tests import mock
+
+
+@pytest.yield_fixture()
+def osd_support_module():
+    with mock.patch("osd_support.module.OSDSupport.get_osdmap"), \
+         mock.patch("osd_support.module.OSDSupport.osd_df"), \
+         mock.patch("osd_support.module.OSDSupport.mon_command", return_value=(0, '', '')):
+        m = OSDSupport.__new__(OSDSupport)
+        m.__init__('osd_support', 0, 0)
+        yield m
diff --git a/src/pybind/mgr/osd_support/tests/test_osd_support.py b/src/pybind/mgr/osd_support/tests/test_osd_support.py
new file mode 100644 (file)
index 0000000..208a3e8
--- /dev/null
@@ -0,0 +1,144 @@
+import pytest
+from .fixtures import osd_support_module as osdsf
+from tests import mock
+
+
+class TestOSDSupport:
+
+    def test_init(self, osdsf):
+        assert osdsf.osd_ids == set()
+        assert osdsf.emptying_osds == set()
+        assert osdsf.check_osds == set()
+        assert osdsf.empty == set()
+
+    def test_osds_not_in_cluster(self, osdsf):
+        assert osdsf.osds_not_in_cluster([1, 2]) == {1, 2}
+
+    @mock.patch("osd_support.module.OSDSupport.get_osds_in_cluster")
+    def test_osds_in_cluster(self, osds_in_cluster, osdsf):
+        osds_in_cluster.return_value = [1]
+        assert osdsf.osds_not_in_cluster([1, 2]) == {2}
+
+    @pytest.mark.parametrize(
+        "is_empty, osd_ids, expected",
+        [
+            (False, {1, 2}, []),
+            (True, {1, 2}, [1, 2]),
+            (None, {1, 2}, []),
+        ]
+    )
+    def test_empty_osd(self, osdsf, is_empty, osd_ids, expected):
+        with mock.patch("osd_support.module.OSDSupport.is_empty", return_value=is_empty):
+            assert osdsf.empty_osds(osd_ids) == expected
+
+    @pytest.mark.parametrize(
+        "pg_count, expected",
+        [
+            (0, True),
+            (1, False),
+            (-1, False),
+            (9999999999999, False),
+        ]
+    )
+    def test_is_emtpy(self, pg_count, expected, osdsf):
+        with mock.patch("osd_support.module.OSDSupport.get_pg_count", return_value=pg_count):
+            assert osdsf.is_empty(1) == expected
+
+    @pytest.mark.parametrize(
+        "osd_ids, reweight_out, expected",
+        [
+            ({1}, [False], False),
+            ({1}, [True], True),
+            ({1, 2}, [True, True], True),
+            ({1, 2}, [True, False], False),
+        ]
+    )
+    def test_reweight_osds(self, osdsf, osd_ids, reweight_out, expected):
+        with mock.patch("osd_support.module.OSDSupport.reweight_osd", side_effect=reweight_out):
+            assert osdsf.reweight_osds(osd_ids) == expected
+
+    @pytest.mark.parametrize(
+        "osd_id, osd_df, expected",
+        [
+            # missing 'nodes' key
+            (1, dict(nodes=[]), -1),
+            # missing 'pgs' key
+            (1, dict(nodes=[dict(id=1)]), -1),
+            # id != osd_id
+            (1, dict(nodes=[dict(id=999, pgs=1)]), -1),
+            # valid
+            (1, dict(nodes=[dict(id=1, pgs=1)]), 1),
+        ]
+    )
+    def test_get_pg_count(self, osdsf, osd_id, osd_df, expected):
+        with mock.patch("osd_support.module.OSDSupport.osd_df", return_value=osd_df):
+            assert osdsf.get_pg_count(osd_id) == expected
+
+    @pytest.mark.parametrize(
+        "osd_id, osd_df, expected",
+        [
+            # missing 'nodes' key
+            (1, dict(nodes=[]), -1.0),
+            # missing 'crush_weight' key
+            (1, dict(nodes=[dict(id=1)]), -1.0),
+            # id != osd_id
+            (1, dict(nodes=[dict(id=999, crush_weight=1)]), -1.0),
+            # valid
+            (1, dict(nodes=[dict(id=1, crush_weight=1)]), float(1)),
+        ]
+    )
+    def test_get_osd_weight(self, osdsf, osd_id, osd_df, expected):
+        with mock.patch("osd_support.module.OSDSupport.osd_df", return_value=osd_df):
+            assert osdsf.get_osd_weight(osd_id) == expected
+
+    @pytest.mark.parametrize(
+        "osd_id, initial_osd_weight, mon_cmd_return, weight, expected",
+        [
+            # is already weighted correctly
+            (1, 1.0, (0, '', ''), 1.0, True),
+            # needs reweight, no errors in mon_cmd
+            (1, 2.0, (0, '', ''), 1.0, True),
+            # needs reweight, errors in mon_cmd
+            (1, 2.0, (1, '', ''), 1.0, False),
+        ]
+    )
+    def test_reweight_osd(self, osdsf, osd_id, initial_osd_weight, mon_cmd_return, weight, expected):
+        with mock.patch("osd_support.module.OSDSupport.get_osd_weight", return_value=initial_osd_weight),\
+             mock.patch("osd_support.module.OSDSupport.mon_command", return_value=mon_cmd_return):
+            assert osdsf.reweight_osd(osd_id, weight=weight) == expected
+
+    @pytest.mark.parametrize(
+        "osd_ids, ok_to_stop, expected",
+        [
+            # no osd_ids provided
+            ({}, [], set()),
+            # all osds are ok_to_stop
+            ({1, 2}, [True], {1, 2}),
+            # osds are ok_to_stop after the second iteration
+            ({1, 2}, [False, True], {2}),
+            # osds are never ok_to_stop, (taking the sample size `(len(osd_ids))` into account),
+            # expected to get a empty set()
+            ({1, 2}, [False, False], set()),
+        ]
+    )
+    def test_find_stop_threshold(self, osdsf, osd_ids, ok_to_stop, expected):
+        with mock.patch("osd_support.module.OSDSupport.ok_to_stop", side_effect=ok_to_stop):
+            assert osdsf.find_osd_stop_threshold(osd_ids) == expected
+
+    @pytest.mark.parametrize(
+        "osd_ids, mon_cmd_return, expected",
+        [
+            # ret is 0
+            ([1], (0, '', ''), True),
+            # no input yields True
+            ([], (0, '', ''), True),
+            # ret is != 0
+            ([1], (-1, '', ''), False),
+            # no input, but ret != 0
+            ([], (-1, '', ''), False),
+        ]
+    )
+    def test_ok_to_stop(self, osdsf, osd_ids, mon_cmd_return, expected):
+        with mock.patch("osd_support.module.OSDSupport.mon_command", return_value=mon_cmd_return):
+            assert osdsf.ok_to_stop(osd_ids) == expected
+