Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package crmsh for openSUSE:Factory checked 
in at 2026-06-29 17:31:08
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/crmsh (Old)
 and      /work/SRC/openSUSE:Factory/.crmsh.new.11887 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "crmsh"

Mon Jun 29 17:31:08 2026 rev:414 rq:1362400 version:5.1.0+20260629.0b862e06

Changes:
--------
--- /work/SRC/openSUSE:Factory/crmsh/crmsh.changes      2026-06-25 
10:58:30.796081890 +0200
+++ /work/SRC/openSUSE:Factory/.crmsh.new.11887/crmsh.changes   2026-06-29 
17:32:26.834318042 +0200
@@ -1,0 +2,12 @@
+Mon Jun 29 11:03:02 UTC 2026 - [email protected]
+
+- Update to version 5.1.0+20260629.0b862e06:
+  * Chore: Changelog: Update ChangeLog for release 5.1.0 rc2
+
+-------------------------------------------------------------------
+Thu Jun 25 08:24:05 UTC 2026 - [email protected]
+
+- Update to version 5.1.0+20260625.11a77666:
+  * Dev: unittests: Add dedicated unit tests for storage_utils
+
+-------------------------------------------------------------------

Old:
----
  crmsh-5.1.0+20260624.349562dd.tar.bz2

New:
----
  crmsh-5.1.0+20260629.0b862e06.tar.bz2

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ crmsh.spec ++++++
--- /var/tmp/diff_new_pack.AcftQ9/_old  2026-06-29 17:32:27.638346369 +0200
+++ /var/tmp/diff_new_pack.AcftQ9/_new  2026-06-29 17:32:27.638346369 +0200
@@ -41,7 +41,7 @@
 Summary:        High Availability cluster command-line interface
 License:        GPL-2.0-or-later
 Group:          %{pkg_group}
-Version:        5.1.0+20260624.349562dd
+Version:        5.1.0+20260629.0b862e06
 Release:        0
 URL:            http://crmsh.github.io
 Source0:        %{name}-%{version}.tar.bz2

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.AcftQ9/_old  2026-06-29 17:32:27.694348343 +0200
+++ /var/tmp/diff_new_pack.AcftQ9/_new  2026-06-29 17:32:27.698348483 +0200
@@ -9,7 +9,7 @@
 </service>
 <service name="tar_scm">
   <param name="url">https://github.com/ClusterLabs/crmsh.git</param>
-  <param 
name="changesrevision">349562dd6312bfaef9755ef04f626b496c66cc7e</param>
+  <param 
name="changesrevision">72564250a68429f7122ef2cebca824495bc9f3d9</param>
 </service>
 </servicedata>
 (No newline at EOF)

++++++ crmsh-5.1.0+20260624.349562dd.tar.bz2 -> 
crmsh-5.1.0+20260629.0b862e06.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh-5.1.0+20260624.349562dd/ChangeLog 
new/crmsh-5.1.0+20260629.0b862e06/ChangeLog
--- old/crmsh-5.1.0+20260624.349562dd/ChangeLog 2026-06-24 06:16:33.000000000 
+0200
+++ new/crmsh-5.1.0+20260629.0b862e06/ChangeLog 2026-06-29 12:31:02.000000000 
+0200
@@ -1,3 +1,39 @@
+* Mon Jun 29 2026 Xin Liang <[email protected]>
+- Release 5.1.0 rc2
+- Dev: Refactor storage helpers out of utils.py (#2132)
+- Chore: unittests: reduce output verbosity and stop printing coverage report 
(#2139)
+- Dev: storage_utils: Rename blkid UUID helper
+- Dev: storage_utils: Refactor storage helpers out of utils.py
+- Dev: bootstrap: Warn about deprecating legacy and 
unencrypted/unauthenticated knet transports (jsc#PED-16433) (#2131)
+- Dev: bootstrap: add a warning about deprecating unencrypted/unauthenticated 
knet transport (jsc#PED-16433)
+- Dev: bootstrap: update warning about deprecating legacy transports 
(jsc#PED-16433)
+- Dev: help: Show alias command info (#2128)
+- Dev: help: Refactor to encapsulate alias help logic in subclass
+- Dev: help: Give the correct level index to fuzzy search for topic help
+- Dev: crm.8.adoc: Improve crm.8.adoc
+- Dev: utils: Add class MultipathInspector to inspect multipath devices (#2116)
+- Fix: sbd: Verify sbd devices on all nodes (#2118)
+- Dev: ui_sbd: Call SBDUtils.verify_sbd_device in multiple places
+- Dev: sbd: Introduce function sbd.SBDUtils.get_sbd_device_metadata_raw
+- Dev: sbd: Compare SBD device UUID optionally
+- Dev: sbd: Call SBDUtils.verify_sbd_device when doing sbd health check
+- Dev: bootstrap: Call join_sbd before changing corosync.conf
+- Dev: log: Lower corosync config tokenizer log level to reduce noise and 
decouple logging from config (#2123)
+- Refactor: crash_test: Use log filters to control output instead of removing 
handlers
+- Refactor: log: replace crmsh.log.setup_logger with logging.setupLogger
+- Dev: log: Use filters to control handler output and simplify logger setup
+- Dev: corosync_config_format: lower the level of debug logs from tokenizer to 
DEBUG2
+- Refactor: log: Decouple logging from config module
+- Fix: sbd: Compare SBD device UUID when adding SBD via sbd stage (#2120)
+- Chore: github-actions: update to node.js 24 actions (#2119)
+- Dev: qdevice: Configure "-p <port>" for /etc/sysconfig/corosync-qnetd on 
qnetd server (#2094)
+- Dev: ui_cluster: Refactor qdevice options validation
+- Dev: ui_cluster: Add --qnetd-port option and deprecate --qdevice-port option
+- Dev: bootstrap: Find and show failed services (#2104)
+- Dev: Separately check if corosync-qdevice.service is successfully started
+- Dev: service_manager: Use systemctl is-active to make sure the service is 
really active
+- Fix: sbd: Set bootstrap_context.diskless_sbd to True when diskless SBD is 
enabled on interactive mode (#2106)
+
 * Thu May 7 2026 Xin Liang <[email protected]>
 - Release 5.1.0 rc1
 - Dev: bootstrap: Load profiles if needed (#2102)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh-5.1.0+20260624.349562dd/data-manifest 
new/crmsh-5.1.0+20260629.0b862e06/data-manifest
--- old/crmsh-5.1.0+20260624.349562dd/data-manifest     2026-06-24 
06:16:33.000000000 +0200
+++ new/crmsh-5.1.0+20260629.0b862e06/data-manifest     2026-06-29 
12:31:02.000000000 +0200
@@ -215,6 +215,7 @@
 test/unittests/test_scripts.py
 test/unittests/test_service_manager.py
 test/unittests/test_sh.py
+test/unittests/test_storage_utils.py
 test/unittests/test_time.py
 test/unittests/test_ui_cluster.py
 test/unittests/test_ui_corosync.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/crmsh-5.1.0+20260624.349562dd/test/unittests/test_storage_utils.py 
new/crmsh-5.1.0+20260629.0b862e06/test/unittests/test_storage_utils.py
--- old/crmsh-5.1.0+20260624.349562dd/test/unittests/test_storage_utils.py      
1970-01-01 01:00:00.000000000 +0100
+++ new/crmsh-5.1.0+20260629.0b862e06/test/unittests/test_storage_utils.py      
2026-06-29 12:31:02.000000000 +0200
@@ -0,0 +1,389 @@
+# Copyright (C) 2026 SUSE LLC
+# See COPYING for license information.
+#
+# unit tests for storage_utils.py
+
+import unittest
+import pytest
+from pathlib import Path
+from unittest import mock
+
+from crmsh import storage_utils, constants
+
+
[email protected]('crmsh.storage_utils.get_dev_info')
+def test_has_dev_partitioned(mock_get_dev_info):
+    mock_get_dev_info.return_value = """
+disk
+part
+    """
+    res = storage_utils.has_dev_partitioned("/dev/sda1")
+    assert res is True
+    mock_get_dev_info.assert_called_once_with("/dev/sda1", "NAME", peer=None)
+
+
[email protected]('crmsh.storage_utils.get_dev_uuid')
+def test_compare_uuid_with_peer_dev_cannot_find_local(mock_get_dev_uuid):
+    mock_get_dev_uuid.return_value = ""
+    with pytest.raises(ValueError) as err:
+        storage_utils.compare_uuid_with_peer_dev(["/dev/sdb1"], "node2")
+    assert str(err.value) == "Cannot find UUID for /dev/sdb1 on local"
+    mock_get_dev_uuid.assert_called_once_with("/dev/sdb1")
+
+
[email protected]('crmsh.storage_utils.get_dev_uuid')
+def test_compare_uuid_with_peer_dev_cannot_find_peer(mock_get_dev_uuid):
+    mock_get_dev_uuid.side_effect = ["1234", ""]
+    with pytest.raises(ValueError) as err:
+        storage_utils.compare_uuid_with_peer_dev(["/dev/sdb1"], "node2")
+    assert str(err.value) == "Cannot find UUID for /dev/sdb1 on node2"
+    mock_get_dev_uuid.assert_has_calls([
+        mock.call("/dev/sdb1"),
+        mock.call("/dev/sdb1", "node2")
+        ])
+
+
[email protected]('crmsh.storage_utils.get_dev_uuid')
+def test_compare_uuid_with_peer_dev(mock_get_dev_uuid):
+    mock_get_dev_uuid.side_effect = ["1234", "5678"]
+    with pytest.raises(ValueError) as err:
+        storage_utils.compare_uuid_with_peer_dev(["/dev/sdb1"], "node2")
+    assert str(err.value) == "UUID of /dev/sdb1 not same with peer node2"
+    mock_get_dev_uuid.assert_has_calls([
+        mock.call("/dev/sdb1"),
+        mock.call("/dev/sdb1", "node2")
+        ])
+
+
[email protected]('crmsh.storage_utils.get_dev_info')
+def test_is_dev_used_for_lvm(mock_dev_info):
+    mock_dev_info.return_value = "lvm"
+    res = storage_utils.is_dev_used_for_lvm("/dev/sda1")
+    assert res is True
+    mock_dev_info.assert_called_once_with("/dev/sda1", "TYPE", peer=None)
+
+
[email protected]('crmsh.storage_utils.get_dev_info')
+def test_is_dev_a_plain_raw_disk_or_partition(mock_dev_info):
+    mock_dev_info.return_value = "raid1\nlvm"
+    res = storage_utils.is_dev_a_plain_raw_disk_or_partition("/dev/md127")
+    assert res is False
+    mock_dev_info.assert_called_once_with("/dev/md127", "TYPE", peer=None)
+
+
[email protected]('crmsh.sh.ClusterShell.get_stdout_or_raise_error')
+def test_get_dev_info(mock_run):
+    mock_run.return_value = "data"
+    res = storage_utils.get_dev_info("/dev/sda1", "TYPE")
+    assert res == "data"
+    mock_run.assert_called_once_with("lsblk -fno TYPE /dev/sda1", None)
+
+
[email protected]('crmsh.storage_utils.get_dev_info')
+def test_get_dev_fs_type(mock_get_info):
+    mock_get_info.return_value = "data"
+    res = storage_utils.get_dev_fs_type("/dev/sda1")
+    assert res == "data"
+    mock_get_info.assert_called_once_with("/dev/sda1", "FSTYPE", peer=None)
+
+
[email protected]('crmsh.storage_utils.get_dev_info')
+def test_get_dev_uuid(mock_get_info):
+    mock_get_info.return_value = "uuid"
+    res = storage_utils.get_dev_uuid("/dev/sda1")
+    assert res == "uuid"
+    mock_get_info.assert_called_once_with("/dev/sda1", "UUID", peer=None)
+
+
[email protected]('crmsh.storage_utils.get_dev_uuid_by_blkid')
[email protected]('crmsh.storage_utils.get_dev_info')
+def test_get_dev_uuid_falls_back_to_blkid(mock_get_info, mock_blkid):
+    mock_get_info.return_value = ""
+    mock_blkid.return_value = "blkid-uuid"
+    res = storage_utils.get_dev_uuid("/dev/sda1")
+    assert res == "blkid-uuid"
+    mock_get_info.assert_called_once_with("/dev/sda1", "UUID", peer=None)
+    mock_blkid.assert_called_once_with("/dev/sda1", None)
+
+
[email protected]('crmsh.sh.ClusterShell.get_stdout_or_raise_error')
+def test_get_dev_uuid_by_blkid(mock_run):
+    mock_run.return_value = '/dev/sda1: UUID="abc-123" TYPE="ext4"'
+    res = storage_utils.get_dev_uuid_by_blkid("/dev/sda1")
+    assert res == "abc-123"
+    mock_run.assert_called_once_with("blkid /dev/sda1", None)
+
+
[email protected]('crmsh.sh.ClusterShell.get_stdout_or_raise_error')
+def test_get_dev_uuid_by_blkid_no_uuid(mock_run):
+    mock_run.return_value = "/dev/sda1: TYPE=\"swap\""
+    res = storage_utils.get_dev_uuid_by_blkid("/dev/sda1")
+    assert res is None
+
+
[email protected]('crmsh.sh.ClusterShell.get_stdout_or_raise_error')
+def test_get_pe_number_except(mock_run):
+    mock_run.return_value = "data"
+    with pytest.raises(ValueError) as err:
+        storage_utils.get_pe_number("vg1")
+    assert str(err.value) == "Cannot find PE on VG(vg1)"
+    mock_run.assert_called_once_with("vgdisplay vg1")
+
+
[email protected]('crmsh.sh.ClusterShell.get_stdout_or_raise_error')
+def test_get_pe_number(mock_run):
+    mock_run.return_value = """
+PE Size               4.00 MiB
+Total PE              1534
+Alloc PE / Size       1534 / 5.99 GiB
+    """
+    res = storage_utils.get_pe_number("vg1")
+    assert res == 1534
+    mock_run.assert_called_once_with("vgdisplay vg1")
+
+
[email protected]('crmsh.sh.ClusterShell.get_stdout_or_raise_error')
+def test_get_all_vg_name(mock_run):
+    mock_run.return_value = """
+--- Volume group ---
+  VG Name               ocfs2-vg
+  System ID
+    """
+    res = storage_utils.get_all_vg_name()
+    assert res == ["ocfs2-vg"]
+    mock_run.assert_called_once_with("vgdisplay")
+
+
[email protected]('crmsh.sh.ClusterShell.get_stdout_or_raise_error')
+def test_has_mount_point_used(mock_run):
+    mock_run.return_value = """
+/dev/vda2 on /usr/local type btrfs 
(rw,relatime,space_cache,subvolid=259,subvol=/@/usr/local)
+/dev/vda2 on /opt type btrfs 
(rw,relatime,space_cache,subvolid=263,subvol=/@/opt)
+/dev/vda2 on /var/lib/docker/btrfs type btrfs 
(rw,relatime,space_cache,subvolid=258,subvol=/@/var)
+    """
+    res = storage_utils.has_mount_point_used("/opt")
+    assert res is True
+    mock_run.assert_called_once_with("mount")
+
+
[email protected]('crmsh.sh.ClusterShell.get_stdout_or_raise_error')
+def test_has_disk_mounted(mock_run):
+    mock_run.return_value = """
+/dev/vda2 on /usr/local type btrfs 
(rw,relatime,space_cache,subvolid=259,subvol=/@/usr/local)
+/dev/vda2 on /opt type btrfs 
(rw,relatime,space_cache,subvolid=263,subvol=/@/opt)
+/dev/vda2 on /var/lib/docker/btrfs type btrfs 
(rw,relatime,space_cache,subvolid=258,subvol=/@/var)
+    """
+    res = storage_utils.has_disk_mounted("/dev/vda2")
+    assert res is True
+    mock_run.assert_called_once_with("mount")
+
+
[email protected]('crmsh.sh.cluster_shell')
+def test_get_non_block_device_nodes(mock_cluster_shell):
+    mock_cluster_shell_inst = mock.Mock()
+    mock_cluster_shell.return_value = mock_cluster_shell_inst
+    mock_cluster_shell_inst.get_rc_stdout_stderr_without_input.return_value = 
(1, None, None)
+    res = storage_utils.get_non_block_device_nodes("/dev/sda1", ["node1"])
+    assert res == ["node1"]
+    
mock_cluster_shell_inst.get_rc_stdout_stderr_without_input.assert_called_once_with("node1",
 "test -b /dev/sda1")
+
+
+def test_detect_duplicate_device_path_no_duplicate():
+    storage_utils.detect_duplicate_device_path(["/dev/sda1", "/dev/sdb1"])
+
+
[email protected]('pathlib.Path.resolve')
+def test_detect_duplicate_device_path_raises(mock_resolve):
+    mock_resolve.return_value = Path("/dev/sda1")
+    with pytest.raises(ValueError) as err:
+        storage_utils.detect_duplicate_device_path(["/dev/sda1", 
"/dev/disk/by-id/sda1"])
+    assert "Duplicated device path detected" in str(err.value)
+    assert "/dev/sda1" in str(err.value)
+
+
[email protected]('crmsh.sh.cluster_shell')
+def test_get_dlm_option_dict(mock_run):
+    mock_run_inst = mock.Mock()
+    mock_run.return_value = mock_run_inst
+    mock_run_inst.get_stdout_or_raise_error.return_value = """
+key1=value1
+key2=value2
+    """
+    res_dict = storage_utils.get_dlm_option_dict()
+    assert res_dict == {
+            "key1": "value1",
+            "key2": "value2"
+            }
+    mock_run_inst.get_stdout_or_raise_error.assert_called_once_with("dlm_tool 
dump_config", None)
+
+
[email protected]('crmsh.storage_utils.get_dlm_option_dict')
+def test_set_dlm_option_exception(mock_get_dict):
+    mock_get_dict.return_value = {
+            "key1": "value1",
+            "key2": "value2"
+            }
+    with pytest.raises(ValueError) as err:
+        storage_utils.set_dlm_option(name="xin")
+    assert str(err.value) == '"name" is not dlm config option'
+
+
[email protected]('crmsh.sh.cluster_shell')
[email protected]('crmsh.storage_utils.get_dlm_option_dict')
+def test_set_dlm_option(mock_get_dict, mock_run):
+    mock_run_inst = mock.Mock()
+    mock_run.return_value = mock_run_inst
+    mock_get_dict.return_value = {
+            "key1": "value1",
+            "key2": "value2"
+            }
+    storage_utils.set_dlm_option(key2="test")
+    mock_run_inst.get_stdout_or_raise_error.assert_called_once_with('dlm_tool 
set_config "key2=test"', None)
+
+
[email protected]('crmsh.xmlutil.CrmMonXmlParser')
+def test_is_dlm_configured(mock_crmmon):
+    mock_crmmon_inst = mock.Mock()
+    mock_crmmon.return_value = mock_crmmon_inst
+    mock_crmmon_inst.is_resource_configured.return_value = True
+    assert storage_utils.is_dlm_configured() is True
+    
mock_crmmon_inst.is_resource_configured.assert_called_once_with(constants.DLM_CONTROLD_RA)
+
+
[email protected]('crmsh.xmlutil.CrmMonXmlParser')
+def test_is_dlm_running(mock_crmmon):
+    mock_crmmon_inst = mock.Mock()
+    mock_crmmon.return_value = mock_crmmon_inst
+    mock_crmmon_inst.is_resource_started.return_value = True
+    assert storage_utils.is_dlm_running() is True
+    
mock_crmmon_inst.is_resource_started.assert_called_once_with(constants.DLM_CONTROLD_RA,
 node=None)
+
+
[email protected]('crmsh.xmlutil.CrmMonXmlParser')
+def test_is_dlm_running_on_node(mock_crmmon):
+    mock_crmmon_inst = mock.Mock()
+    mock_crmmon.return_value = mock_crmmon_inst
+    mock_crmmon_inst.is_resource_started.return_value = False
+    assert storage_utils.is_dlm_running(on_node="node1") is False
+    
mock_crmmon_inst.is_resource_started.assert_called_once_with(constants.DLM_CONTROLD_RA,
 node="node1")
+
+
[email protected]('crmsh.storage_utils.is_dlm_configured')
+def test_check_no_quorum_policy_with_dlm_return(mock_dlm):
+    mock_dlm.return_value = False
+    storage_utils.check_no_quorum_policy_with_dlm()
+    mock_dlm.assert_called_once_with()
+
+
[email protected]('logging.Logger.warning')
[email protected]('crmsh.utils.get_property')
[email protected]('crmsh.storage_utils.is_dlm_configured')
+def test_check_no_quorum_policy_with_dlm(mock_dlm, mock_get_property, 
mock_warn):
+    mock_dlm.return_value = True
+    mock_get_property.return_value = "stop"
+    storage_utils.check_no_quorum_policy_with_dlm()
+    mock_dlm.assert_called_once_with()
+    mock_get_property.assert_called_once_with("no-quorum-policy")
+    mock_warn.assert_called_once_with('The DLM cluster best practice suggests 
to set the cluster property "no-quorum-policy=freeze"')
+
+
+class TestMultipathInspector(unittest.TestCase):
+
+    @mock.patch('crmsh.sh.cluster_shell')
+    def test_init(self, mock_cluster_shell):
+        """Test MultipathInspector initialization"""
+        mock_shell_inst = mock.Mock()
+        mock_cluster_shell.return_value = mock_shell_inst
+        mock_shell_inst.get_rc_stdout_stderr_without_input.side_effect = [
+            (0, "sda", ""),  # lsblk output for parent device
+            (0, "dev multipath\nsda mpatha", "")  # multipathd show paths 
output
+        ]
+
+        inspector = storage_utils.MultipathInspector("/dev/sda1")
+
+        assert inspector._shell == mock_shell_inst
+        assert inspector._device_info.device == "/dev/sda1"
+        assert inspector._device_info.parent_device == "sda"
+        assert inspector._device_info.under_multipath is True
+
+    @mock.patch('crmsh.sh.cluster_shell')
+    def test_get_parent_device(self, mock_cluster_shell):
+        """Test _get_parent_device method"""
+        mock_shell_inst = mock.Mock()
+        mock_cluster_shell.return_value = mock_shell_inst
+        mock_shell_inst.get_rc_stdout_stderr_without_input.side_effect = [
+            (0, "sda", ""),  # lsblk output for __init__
+            (0, "", ""),  # multipathd show paths output for __init__
+            (0, "sda", "")  # lsblk output for test call
+        ]
+
+        inspector = storage_utils.MultipathInspector("/dev/sda1")
+        parent = inspector._get_parent_device("/dev/sda1")
+
+        assert parent == "sda"
+
+    @mock.patch('crmsh.sh.cluster_shell')
+    def test_get_multipath_mapping(self, mock_cluster_shell):
+        """Test _get_multipath_mapping method with valid output"""
+        mock_shell_inst = mock.Mock()
+        mock_cluster_shell.return_value = mock_shell_inst
+        multipathd_output = """dev multipath
+sda mpatha
+sdb mpatha
+sdc mpathb"""
+        mock_shell_inst.get_rc_stdout_stderr_without_input.side_effect = [
+            (0, "sda", ""),  # lsblk for __init__
+            (0, multipathd_output, ""),  # multipathd for __init__
+            (0, multipathd_output, "")  # multipathd for test call
+        ]
+
+        inspector = storage_utils.MultipathInspector("/dev/sda1")
+        mapping = inspector._get_multipath_mapping()
+
+        assert mapping == {"sda": "mpatha", "sdb": "mpatha", "sdc": "mpathb"}
+
+    @mock.patch('crmsh.sh.cluster_shell')
+    def test_inspect_device_under_multipath(self, mock_cluster_shell):
+        """Test _inspect method when device is under multipath"""
+        mock_shell_inst = mock.Mock()
+        mock_cluster_shell.return_value = mock_shell_inst
+        mock_shell_inst.get_rc_stdout_stderr_without_input.side_effect = [
+            (0, "sda", ""),
+            (0, "dev multipath\nsda mpatha", "")
+        ]
+
+        inspector = storage_utils.MultipathInspector("/dev/sda1")
+        device_info = inspector._device_info
+
+        assert device_info.device == "/dev/sda1"
+        assert device_info.parent_device == "sda"
+        assert device_info.under_multipath is True
+
+    @mock.patch('crmsh.sh.cluster_shell')
+    def test_is_under_multipath_true(self, mock_cluster_shell):
+        """Test _is_under_multipath returns True"""
+        mock_shell_inst = mock.Mock()
+        mock_cluster_shell.return_value = mock_shell_inst
+        mock_shell_inst.get_rc_stdout_stderr_without_input.side_effect = [
+            (0, "sda", ""),
+            (0, "dev multipath\nsda mpatha", "")
+        ]
+
+        inspector = storage_utils.MultipathInspector("/dev/sda1")
+
+        assert inspector._is_under_multipath() is True
+
+    @mock.patch('crmsh.sh.cluster_shell')
+    def test_check_device_under_multipath_raises_error(self, 
mock_cluster_shell):
+        """Test check_device_under_multipath raises ValueError when device is 
under multipath"""
+        mock_shell_inst = mock.Mock()
+        mock_cluster_shell.return_value = mock_shell_inst
+        mock_shell_inst.get_rc_stdout_stderr_without_input.side_effect = [
+            (0, "sda", ""),
+            (0, "dev multipath\nsda mpatha", "")
+        ]
+
+        with pytest.raises(ValueError) as exc_info:
+            
storage_utils.MultipathInspector.check_device_under_multipath("/dev/sda1")
+
+        assert str(exc_info.value) == "Device /dev/sda1 is under multipath, 
please provide the multipath device instead"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/crmsh-5.1.0+20260624.349562dd/test/unittests/test_utils.py 
new/crmsh-5.1.0+20260629.0b862e06/test/unittests/test_utils.py
--- old/crmsh-5.1.0+20260624.349562dd/test/unittests/test_utils.py      
2026-06-24 06:16:33.000000000 +0200
+++ new/crmsh-5.1.0+20260629.0b862e06/test/unittests/test_utils.py      
2026-06-29 12:31:02.000000000 +0200
@@ -13,7 +13,7 @@
 from itertools import chain
 
 import crmsh.utils
-from crmsh import utils, storage_utils, config, tmpfiles, constants, options
+from crmsh import utils, config, tmpfiles, constants, options
 
 logging.basicConfig(level=logging.DEBUG)
 
@@ -756,123 +756,6 @@
     assert utils.re_split_string('[; ]', "/dev/sda1 ") == ["/dev/sda1"]
 
 
[email protected]('crmsh.storage_utils.get_dev_info')
-def test_has_dev_partitioned(mock_get_dev_info):
-    mock_get_dev_info.return_value = """
-disk
-part
-    """
-    res = storage_utils.has_dev_partitioned("/dev/sda1")
-    assert res is True
-    mock_get_dev_info.assert_called_once_with("/dev/sda1", "NAME", peer=None)
-
-
[email protected]('crmsh.storage_utils.get_dev_uuid')
-def test_compare_uuid_with_peer_dev_cannot_find_local(mock_get_dev_uuid):
-    mock_get_dev_uuid.return_value = ""
-    with pytest.raises(ValueError) as err:
-        storage_utils.compare_uuid_with_peer_dev(["/dev/sdb1"], "node2")
-    assert str(err.value) == "Cannot find UUID for /dev/sdb1 on local"
-    mock_get_dev_uuid.assert_called_once_with("/dev/sdb1")
-
-
[email protected]('crmsh.storage_utils.get_dev_uuid')
-def test_compare_uuid_with_peer_dev_cannot_find_peer(mock_get_dev_uuid):
-    mock_get_dev_uuid.side_effect = ["1234", ""]
-    with pytest.raises(ValueError) as err:
-        storage_utils.compare_uuid_with_peer_dev(["/dev/sdb1"], "node2")
-    assert str(err.value) == "Cannot find UUID for /dev/sdb1 on node2"
-    mock_get_dev_uuid.assert_has_calls([
-        mock.call("/dev/sdb1"),
-        mock.call("/dev/sdb1", "node2")
-        ])
-
-
[email protected]('crmsh.storage_utils.get_dev_uuid')
-def test_compare_uuid_with_peer_dev(mock_get_dev_uuid):
-    mock_get_dev_uuid.side_effect = ["1234", "5678"]
-    with pytest.raises(ValueError) as err:
-        storage_utils.compare_uuid_with_peer_dev(["/dev/sdb1"], "node2")
-    assert str(err.value) == "UUID of /dev/sdb1 not same with peer node2"
-    mock_get_dev_uuid.assert_has_calls([
-        mock.call("/dev/sdb1"),
-        mock.call("/dev/sdb1", "node2")
-        ])
-
-
[email protected]('crmsh.storage_utils.get_dev_info')
-def test_is_dev_used_for_lvm(mock_dev_info):
-    mock_dev_info.return_value = "lvm"
-    res = storage_utils.is_dev_used_for_lvm("/dev/sda1")
-    assert res is True
-    mock_dev_info.assert_called_once_with("/dev/sda1", "TYPE", peer=None)
-
-
[email protected]('crmsh.storage_utils.get_dev_info')
-def test_is_dev_a_plain_raw_disk_or_partition(mock_dev_info):
-    mock_dev_info.return_value = "raid1\nlvm"
-    res = storage_utils.is_dev_a_plain_raw_disk_or_partition("/dev/md127")
-    assert res is False
-    mock_dev_info.assert_called_once_with("/dev/md127", "TYPE", peer=None)
-
-
[email protected]('crmsh.sh.ClusterShell.get_stdout_or_raise_error')
-def test_get_dev_info(mock_run):
-    mock_run.return_value = "data"
-    res = storage_utils.get_dev_info("/dev/sda1", "TYPE")
-    assert res == "data"
-    mock_run.assert_called_once_with("lsblk -fno TYPE /dev/sda1", None)
-
-
[email protected]('crmsh.storage_utils.get_dev_info')
-def test_get_dev_fs_type(mock_get_info):
-    mock_get_info.return_value = "data"
-    res = storage_utils.get_dev_fs_type("/dev/sda1")
-    assert res == "data"
-    mock_get_info.assert_called_once_with("/dev/sda1", "FSTYPE", peer=None)
-
-
[email protected]('crmsh.storage_utils.get_dev_info')
-def test_get_dev_uuid(mock_get_info):
-    mock_get_info.return_value = "uuid"
-    res = storage_utils.get_dev_uuid("/dev/sda1")
-    assert res == "uuid"
-    mock_get_info.assert_called_once_with("/dev/sda1", "UUID", peer=None)
-
-
[email protected]('crmsh.sh.ClusterShell.get_stdout_or_raise_error')
-def test_get_pe_number_except(mock_run):
-    mock_run.return_value = "data"
-    with pytest.raises(ValueError) as err:
-        storage_utils.get_pe_number("vg1")
-    assert str(err.value) == "Cannot find PE on VG(vg1)"
-    mock_run.assert_called_once_with("vgdisplay vg1")
-
-
[email protected]('crmsh.sh.ClusterShell.get_stdout_or_raise_error')
-def test_get_pe_number(mock_run):
-    mock_run.return_value = """
-PE Size               4.00 MiB
-Total PE              1534
-Alloc PE / Size       1534 / 5.99 GiB
-    """
-    res = storage_utils.get_pe_number("vg1")
-    assert res == 1534
-    mock_run.assert_called_once_with("vgdisplay vg1")
-
-
[email protected]('crmsh.sh.ClusterShell.get_stdout_or_raise_error')
-def test_get_all_vg_name(mock_run):
-    mock_run.return_value = """
---- Volume group ---
-  VG Name               ocfs2-vg
-  System ID
-    """
-    res = storage_utils.get_all_vg_name()
-    assert res == ["ocfs2-vg"]
-    mock_run.assert_called_once_with("vgdisplay")
-
-
 @mock.patch('crmsh.utils.randomword')
 def test_gen_unused_id(mock_rand):
     mock_rand.return_value = "1234xxxx"
@@ -901,30 +784,6 @@
     mock_cib.refresh.assert_called_once_with()
 
 
[email protected]('crmsh.sh.ClusterShell.get_stdout_or_raise_error')
-def test_has_mount_point_used(mock_run):
-    mock_run.return_value = """
-/dev/vda2 on /usr/local type btrfs 
(rw,relatime,space_cache,subvolid=259,subvol=/@/usr/local)
-/dev/vda2 on /opt type btrfs 
(rw,relatime,space_cache,subvolid=263,subvol=/@/opt)
-/dev/vda2 on /var/lib/docker/btrfs type btrfs 
(rw,relatime,space_cache,subvolid=258,subvol=/@/var)
-    """
-    res = storage_utils.has_mount_point_used("/opt")
-    assert res is True
-    mock_run.assert_called_once_with("mount")
-
-
[email protected]('crmsh.sh.ClusterShell.get_stdout_or_raise_error')
-def test_has_disk_mounted(mock_run):
-    mock_run.return_value = """
-/dev/vda2 on /usr/local type btrfs 
(rw,relatime,space_cache,subvolid=259,subvol=/@/usr/local)
-/dev/vda2 on /opt type btrfs 
(rw,relatime,space_cache,subvolid=263,subvol=/@/opt)
-/dev/vda2 on /var/lib/docker/btrfs type btrfs 
(rw,relatime,space_cache,subvolid=258,subvol=/@/var)
-    """
-    res = storage_utils.has_disk_mounted("/dev/vda2")
-    assert res is True
-    mock_run.assert_called_once_with("mount")
-
-
 @mock.patch('crmsh.sbd.SBDUtils.is_using_diskless_sbd')
 @mock.patch('crmsh.sh.ClusterShell.get_stdout_or_raise_error')
 def test_has_fence_device_registered(mock_run, mock_diskless):
@@ -939,16 +798,6 @@
     mock_diskless.assert_called_once_with()
 
 
[email protected]('crmsh.sh.cluster_shell')
-def test_get_non_block_device_nodes(mock_cluster_shell):
-    mock_cluster_shell_inst = mock.Mock()
-    mock_cluster_shell.return_value = mock_cluster_shell_inst
-    mock_cluster_shell_inst.get_rc_stdout_stderr_without_input.return_value = 
(1, None, None)
-    res = storage_utils.get_non_block_device_nodes("/dev/sda1", ["node1"])
-    assert res == ["node1"]
-    
mock_cluster_shell_inst.get_rc_stdout_stderr_without_input.assert_called_once_with("node1",
 "test -b /dev/sda1")    
-
-
 @mock.patch('crmsh.utils.ssh_port_reachable_check')
 @mock.patch('crmsh.xmlutil.CrmMonXmlParser')
 def test_check_all_nodes_reachable_dead_nodes(mock_xml, mock_reachable):
@@ -987,55 +836,6 @@
     mock_run.assert_called_once_with("systemd-detect-virt")
 
 
[email protected]('crmsh.sh.cluster_shell')
-def test_get_dlm_option_dict(mock_run):
-    mock_run_inst = mock.Mock()
-    mock_run.return_value = mock_run_inst
-    mock_run_inst.get_stdout_or_raise_error.return_value = """
-key1=value1
-key2=value2
-    """
-    res_dict = storage_utils.get_dlm_option_dict()
-    assert res_dict == {
-            "key1": "value1",
-            "key2": "value2"
-            }
-    mock_run_inst.get_stdout_or_raise_error.assert_called_once_with("dlm_tool 
dump_config", None)
-
-
[email protected]('crmsh.storage_utils.get_dlm_option_dict')
-def test_set_dlm_option_exception(mock_get_dict):
-    mock_get_dict.return_value = {
-            "key1": "value1",
-            "key2": "value2"
-            }
-    with pytest.raises(ValueError) as err:
-        storage_utils.set_dlm_option(name="xin")
-    assert str(err.value) == '"name" is not dlm config option'
-
-
[email protected]('crmsh.sh.cluster_shell')
[email protected]('crmsh.storage_utils.get_dlm_option_dict')
-def test_set_dlm_option(mock_get_dict, mock_run):
-    mock_run_inst = mock.Mock()
-    mock_run.return_value = mock_run_inst
-    mock_get_dict.return_value = {
-            "key1": "value1",
-            "key2": "value2"
-            }
-    storage_utils.set_dlm_option(key2="test")
-    mock_run_inst.get_stdout_or_raise_error.assert_called_once_with('dlm_tool 
set_config "key2=test"', None)
-
-
[email protected]('crmsh.xmlutil.CrmMonXmlParser')
-def test_is_dlm_configured(mock_crmmon):
-    mock_crmmon_inst = mock.Mock()
-    mock_crmmon.return_value = mock_crmmon_inst
-    mock_crmmon_inst.is_resource_configured.return_value = True
-    assert storage_utils.is_dlm_configured() is True
-    
mock_crmmon_inst.is_resource_configured.assert_called_once_with(constants.DLM_CONTROLD_RA)
-
-
 @mock.patch('crmsh.xmlutil.CrmMonXmlParser')
 def test_cluster_with_quorum(mock_crmmon):
     mock_crmmon_inst = mock.Mock()
@@ -1150,25 +950,6 @@
     mock_msec.assert_has_calls([mock.call("10s"), mock.call("10")])
 
 
[email protected]('crmsh.storage_utils.is_dlm_configured')
-def test_check_no_quorum_policy_with_dlm_return(mock_dlm):
-    mock_dlm.return_value = False
-    storage_utils.check_no_quorum_policy_with_dlm()
-    mock_dlm.assert_called_once_with()
-
-
[email protected]('logging.Logger.warning')
[email protected]('crmsh.utils.get_property')
[email protected]('crmsh.storage_utils.is_dlm_configured')
-def test_check_no_quorum_policy_with_dlm(mock_dlm, mock_get_property, 
mock_warn):
-    mock_dlm.return_value = True
-    mock_get_property.return_value = "stop"
-    storage_utils.check_no_quorum_policy_with_dlm()
-    mock_dlm.assert_called_once_with()
-    mock_get_property.assert_called_once_with("no-quorum-policy")
-    mock_warn.assert_called_once_with('The DLM cluster best practice suggests 
to set the cluster property "no-quorum-policy=freeze"')
-
-
 @mock.patch('crmsh.corosync.is_qdevice_configured')
 @mock.patch('crmsh.utils.list_cluster_nodes')
 def test_is_2node_cluster_without_qdevice(mock_list, mock_is_qdevice):
@@ -1479,104 +1260,3 @@
 
     mock_error.assert_called_once_with("From the view of node '%s', node '%s' 
is not a member of the cluster", 'node1', 'node2')
 
-
-class TestMultipathInspector(unittest.TestCase):
-
-    @mock.patch('crmsh.sh.cluster_shell')
-    def test_init(self, mock_cluster_shell):
-        """Test MultipathInspector initialization"""
-        mock_shell_inst = mock.Mock()
-        mock_cluster_shell.return_value = mock_shell_inst
-        mock_shell_inst.get_rc_stdout_stderr_without_input.side_effect = [
-            (0, "sda", ""),  # lsblk output for parent device
-            (0, "dev multipath\nsda mpatha", "")  # multipathd show paths 
output
-        ]
-
-        inspector = storage_utils.MultipathInspector("/dev/sda1")
-
-        assert inspector._shell == mock_shell_inst
-        assert inspector._device_info.device == "/dev/sda1"
-        assert inspector._device_info.parent_device == "sda"
-        assert inspector._device_info.under_multipath is True
-
-    @mock.patch('crmsh.sh.cluster_shell')
-    def test_get_parent_device(self, mock_cluster_shell):
-        """Test _get_parent_device method"""
-        mock_shell_inst = mock.Mock()
-        mock_cluster_shell.return_value = mock_shell_inst
-        mock_shell_inst.get_rc_stdout_stderr_without_input.side_effect = [
-            (0, "sda", ""),  # lsblk output for __init__
-            (0, "", ""),  # multipathd show paths output for __init__
-            (0, "sda", "")  # lsblk output for test call
-        ]
-
-        inspector = storage_utils.MultipathInspector("/dev/sda1")
-        parent = inspector._get_parent_device("/dev/sda1")
-
-        assert parent == "sda"
-
-    @mock.patch('crmsh.sh.cluster_shell')
-    def test_get_multipath_mapping(self, mock_cluster_shell):
-        """Test _get_multipath_mapping method with valid output"""
-        mock_shell_inst = mock.Mock()
-        mock_cluster_shell.return_value = mock_shell_inst
-        multipathd_output = """dev multipath
-sda mpatha
-sdb mpatha
-sdc mpathb"""
-        mock_shell_inst.get_rc_stdout_stderr_without_input.side_effect = [
-            (0, "sda", ""),  # lsblk for __init__
-            (0, multipathd_output, ""),  # multipathd for __init__
-            (0, multipathd_output, "")  # multipathd for test call
-        ]
-
-        inspector = storage_utils.MultipathInspector("/dev/sda1")
-        mapping = inspector._get_multipath_mapping()
-
-        assert mapping == {"sda": "mpatha", "sdb": "mpatha", "sdc": "mpathb"}
-
-    @mock.patch('crmsh.sh.cluster_shell')
-    def test_inspect_device_under_multipath(self, mock_cluster_shell):
-        """Test _inspect method when device is under multipath"""
-        mock_shell_inst = mock.Mock()
-        mock_cluster_shell.return_value = mock_shell_inst
-        mock_shell_inst.get_rc_stdout_stderr_without_input.side_effect = [
-            (0, "sda", ""),
-            (0, "dev multipath\nsda mpatha", "")
-        ]
-
-        inspector = storage_utils.MultipathInspector("/dev/sda1")
-        device_info = inspector._device_info
-
-        assert device_info.device == "/dev/sda1"
-        assert device_info.parent_device == "sda"
-        assert device_info.under_multipath is True
-
-    @mock.patch('crmsh.sh.cluster_shell')
-    def test_is_under_multipath_true(self, mock_cluster_shell):
-        """Test _is_under_multipath returns True"""
-        mock_shell_inst = mock.Mock()
-        mock_cluster_shell.return_value = mock_shell_inst
-        mock_shell_inst.get_rc_stdout_stderr_without_input.side_effect = [
-            (0, "sda", ""),
-            (0, "dev multipath\nsda mpatha", "")
-        ]
-
-        inspector = storage_utils.MultipathInspector("/dev/sda1")
-
-        assert inspector._is_under_multipath() is True
-
-    @mock.patch('crmsh.sh.cluster_shell')
-    def test_check_device_under_multipath_raises_error(self, 
mock_cluster_shell):
-        """Test check_device_under_multipath raises ValueError when device is 
under multipath"""
-        mock_shell_inst = mock.Mock()
-        mock_cluster_shell.return_value = mock_shell_inst
-        mock_shell_inst.get_rc_stdout_stderr_without_input.side_effect = [
-            (0, "sda", ""),
-            (0, "dev multipath\nsda mpatha", "")
-        ]
-
-        with pytest.raises(ValueError) as exc_info:
-            
storage_utils.MultipathInspector.check_device_under_multipath("/dev/sda1")
-
-        assert str(exc_info.value) == "Device /dev/sda1 is under multipath, 
please provide the multipath device instead"

Reply via email to